Skip to content

Commit 6d7a44c

Browse files
authored
Merge pull request #370 from sondrebr/add-gitlab-support-event-info-classes
[gitlab] Add GitLab connection and EventInfo classes
2 parents bef4dfb + 373e6db commit 6d7a44c

7 files changed

Lines changed: 565 additions & 8 deletions

File tree

app.cfg.example

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717

1818
# Also see documentation at https://github.com/EESSI/eessi-bot-software-layer/blob/main/README.md#step5.5
1919

20+
[git]
21+
# Name of the Git hosting platform (supported values are 'github' and 'gitlab')
22+
hosting_platform = github
23+
2024
[github]
2125
# API timeout, time limit for requests to GitHub's REST API
2226
api_timeout = 10
@@ -43,6 +47,20 @@ installation_id = 12345678
4347
# path to the private key that was generated when the GitHub App was registered
4448
private_key = PATH_TO_PRIVATE_KEY
4549

50+
[gitlab]
51+
# NOTE: Access token required for GitLab:
52+
# https://docs.gitlab.com/user/project/settings/project_access_tokens/#bot-users-for-projects
53+
# Must be stored in environment variable 'GITLAB_PROJECT_ACCESS_TOKEN'.
54+
55+
# API timeout, time limit for requests to GitLab's REST API
56+
api_timeout = 10
57+
58+
# Name used to refer to your bot instance - see comment for github.app_name config
59+
bot_name = MY-bot
60+
61+
# The base URL of your GitLab instance
62+
instance_url = https://gitlab.com
63+
4664

4765
[bot_control]
4866
# which GH accounts have the permission to send commands to the bot

connections/gitlab.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# This file is part of the EESSI build-and-deploy bot,
2+
# see https://github.com/EESSI/eessi-bot-software-layer
3+
#
4+
# The bot helps with requests to add software installations to the
5+
# EESSI software layer, see https://github.com/EESSI/software-layer
6+
#
7+
# author: Sondre Bergsvaag Risanger (@sondrebr)
8+
#
9+
# license: GPLv2
10+
#
11+
12+
# Standard library imports
13+
import os
14+
15+
# Third party imports (anything installed into the local Python environment)
16+
import gitlab
17+
18+
# Local application imports (anything from EESSI/eessi-bot-software-layer)
19+
from tools import config, logging
20+
21+
22+
_gl = None
23+
24+
25+
def verify_connection(gl):
26+
"""
27+
Verifies connection to GitLab. Exits if verification fails.
28+
29+
Args:
30+
Instance of gitlab.Gitlab (from python-gitlab)
31+
32+
Returns:
33+
None (implicit)
34+
"""
35+
try:
36+
# auth tests the instance's credentials by retrieving the access token user
37+
gl.auth()
38+
if type(gl.user) is not gl._objects.CurrentUser:
39+
raise Exception("'user' attribute of Gitlab class instance is not of type 'CurrentUser'.")
40+
except Exception as err:
41+
logging.error(f"Failed to verify GitLab connection: {err}")
42+
43+
44+
def connect():
45+
"""
46+
Creates a gitlab.Gitlab instance (from python-gitlab), then verifies the connection to GitLab.
47+
48+
Args:
49+
No arguments
50+
51+
Returns:
52+
None (implicit)
53+
"""
54+
global _gl
55+
cfg = config.read_config()
56+
gitlab_cfg = cfg[config.SECTION_GITLAB]
57+
timeout = int(gitlab_cfg.get(config.GITLAB_SETTING_API_TIMEOUT, 10))
58+
url = gitlab_cfg.get(config.GITLAB_SETTING_INSTANCE_URL)
59+
60+
access_token = os.getenv('GITLAB_PROJECT_ACCESS_TOKEN')
61+
if access_token is None:
62+
logging.error("GitLab token is not available via $GITLAB_PROJECT_ACCESS_TOKEN!")
63+
else:
64+
del os.environ['GITLAB_PROJECT_ACCESS_TOKEN']
65+
66+
_gl = gitlab.Gitlab(url, access_token)
67+
_gl.timeout = timeout
68+
_gl.retry_transient_errors = True
69+
verify_connection(_gl)
70+
71+
72+
def get_instance():
73+
"""
74+
Returns a gitlab.Gitlab instance. Creates an instance if one does not exist,
75+
otherwise verifies the existing instance.
76+
77+
Args:
78+
No arguments
79+
80+
Returns:
81+
Instance of gitlab.Gitlab (from python-gitlab)
82+
"""
83+
if not _gl:
84+
connect()
85+
else:
86+
verify_connection(_gl)
87+
return _gl

eessi_bot_event_handler.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
from tools.args import event_handler_parse
3838
from tools.commands import EESSIBotCommand, EESSIBotCommandError, \
3939
contains_any_bot_command, get_bot_command
40+
from tools.event_info import create_event_info_instance
41+
from tools.git import connect_to_git_hosting_platform, get_git_hosting_platform
4042
from tools.permissions import check_command_permission
4143
from tools.pr_comments import ChatLevels, create_comment
4244

@@ -95,12 +97,18 @@
9597
config.DOWNLOAD_PR_COMMENTS_SETTING_PR_DIFF_TIP], # required
9698
config.SECTION_EVENT_HANDLER: [
9799
config.EVENT_HANDLER_SETTING_LOG_PATH], # required
100+
config.SECTION_GIT: [
101+
config.GIT_SETTING_HOSTING_PLATFORM], # required
98102
config.SECTION_GITHUB: [
99-
config.GITHUB_SETTING_API_TIMEOUT, # required
100-
config.GITHUB_SETTING_APP_ID, # required
101-
config.GITHUB_SETTING_APP_NAME, # required
102-
config.GITHUB_SETTING_INSTALLATION_ID, # required
103-
config.GITHUB_SETTING_PRIVATE_KEY], # required
103+
config.GITHUB_SETTING_API_TIMEOUT, # required for github
104+
config.GITHUB_SETTING_APP_ID, # required for github
105+
config.GITHUB_SETTING_APP_NAME, # required for github
106+
config.GITHUB_SETTING_INSTALLATION_ID, # required for github
107+
config.GITHUB_SETTING_PRIVATE_KEY], # required for github
108+
config.SECTION_GITLAB: [
109+
config.GITLAB_SETTING_API_TIMEOUT, # required for gitlab
110+
config.GITLAB_SETTING_BOT_NAME, # required for gitlab
111+
config.GITLAB_SETTING_INSTANCE_URL], # required for gitlab
104112
# the poll interval setting is required for the alternative job handover
105113
# protocol (delayed_begin)
106114
config.SECTION_JOB_MANAGER: [
@@ -133,7 +141,8 @@ def __init__(self, *args, **kwargs):
133141
EESSIBotSoftwareLayer constructor. Calls constructor of PyGHee and
134142
initializes some configuration settings.
135143
"""
136-
super(EESSIBotSoftwareLayer, self).__init__(*args, **kwargs)
144+
event_source = get_git_hosting_platform()
145+
super(EESSIBotSoftwareLayer, self).__init__(event_source, *args, **kwargs)
137146

138147
self.cfg = config.read_config()
139148
event_handler_cfg = self.cfg[config.SECTION_EVENT_HANDLER]
@@ -157,6 +166,22 @@ def log(self, msg, *args):
157166
msg = "[%s]: %s" % (funcname, msg)
158167
log(msg, log_file=self.logfile)
159168

169+
def handle_event(self, event_info, log_file=None):
170+
"""
171+
Override of PyGHee's handle_event method.
172+
Create EventInfo instance using event_info,
173+
then pass that to PyGHee's handle_event method.
174+
175+
Args:
176+
event_info (dict): event received by event_handler
177+
log_file (string): path to log messages to
178+
179+
Returns:
180+
None (implicit)
181+
"""
182+
event_info_object = create_event_info_instance(event_info)
183+
super().handle_event(event_info_object, log_file)
184+
160185
def handle_issue_comment_event(self, event_info, log_file=None):
161186
"""
162187
Handle events of type issue_comment. Main action is to parse new issue
@@ -833,7 +858,9 @@ def main():
833858
else:
834859
print("Configuration check: FAILED")
835860
sys.exit(1)
836-
github.connect()
861+
862+
# Verify that the event handler is able to connect to the Git hosting platform
863+
connect_to_git_hosting_platform()
837864

838865
if opts.file:
839866
app = create_app(klass=EESSIBotSoftwareLayer)

requirements.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
# author: Bob Droege (@bedroge)
88
# author: Kenneth Hoste (@boegel)
99
# author: Thomas Roeblitz (@trz42)
10+
# author: Sondre Bergsvaag Risanger (@sondrebr)
1011
#
1112
# license: GPLv2
1213
#
1314
PyGithub
15+
python-gitlab==6.5.0;python_version=="3.9" # Last version with Python 3.9 support
16+
python-gitlab==8.3.0;python_version>="3.10" # Most recent version on 2026-05-04
1417
Waitress>=3.0.1 # required to fix vulnerabilities detected by scorecards
1518
cryptography>=44.0.1 # required to fix vulnerabilities detected by scorecards
16-
PyGHee>=0.0.3
19+
PyGHee @ git+https://github.com/boegel/PyGHee.git@c5e10632a45db5ca94f5cbf87ac7a90a2064e8fd # Pin commit with GL support
1720
retry

tools/config.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
# (none yet)
2424

2525
# Local application imports (anything from EESSI/eessi-bot-software-layer)
26+
from .git import get_git_hosting_platform, SUPPORTED_GIT_HOSTS
2627
from .logging import error
2728

2829
# define configuration constants
@@ -95,13 +96,21 @@
9596
FINISHED_JOB_COMMENTS_SETTING_JOB_RESULT_UNKNOWN_FMT = 'job_result_unknown_fmt'
9697
FINISHED_JOB_COMMENTS_SETTING_JOB_TEST_UNKNOWN_FMT = 'job_test_unknown_fmt'
9798

99+
SECTION_GIT = 'git'
100+
GIT_SETTING_HOSTING_PLATFORM = 'hosting_platform'
101+
98102
SECTION_GITHUB = 'github'
99103
GITHUB_SETTING_API_TIMEOUT = 'api_timeout'
100104
GITHUB_SETTING_APP_ID = 'app_id'
101105
GITHUB_SETTING_APP_NAME = 'app_name'
102106
GITHUB_SETTING_INSTALLATION_ID = 'installation_id'
103107
GITHUB_SETTING_PRIVATE_KEY = 'private_key'
104108

109+
SECTION_GITLAB = 'gitlab'
110+
GITLAB_SETTING_API_TIMEOUT = 'api_timeout'
111+
GITLAB_SETTING_BOT_NAME = 'bot_name'
112+
GITLAB_SETTING_INSTANCE_URL = 'instance_url'
113+
105114
SECTION_JOB_MANAGER = 'job_manager'
106115
JOB_MANAGER_SETTING_LOG_PATH = 'log_path'
107116
JOB_MANAGER_SETTING_JOB_IDS_DIR = 'job_ids_dir'
@@ -207,9 +216,13 @@ def check_cfg_settings(req_settings, path="app.cfg"):
207216
"""
208217
# TODO argument path is not being used
209218
cfg = read_config()
219+
git_host = get_git_hosting_platform(cfg)
210220
# iterate over keys in req_settings which correspond to sections ([name])
211221
# in the configuration file (.ini format)
212222
for section in req_settings.keys():
223+
# Skip checking the GitLab section if the bot is configured for GitHub and vice versa
224+
if git_host and (section in SUPPORTED_GIT_HOSTS) and (section != git_host):
225+
continue
213226
if section not in cfg:
214227
error(f'Missing section "{section}" in configuration file {path}.')
215228
# iterate over list elements required for the current section

0 commit comments

Comments
 (0)