Skip to content
Open
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
18 changes: 18 additions & 0 deletions app.cfg.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

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

[git]
# Name of the Git hosting platform (supported values are 'github' and 'gitlab')
hosting_platform = github

[github]
# API timeout, time limit for requests to GitHub's REST API
api_timeout = 10
Expand All @@ -43,6 +47,20 @@ installation_id = 12345678
# path to the private key that was generated when the GitHub App was registered
private_key = PATH_TO_PRIVATE_KEY

[gitlab]
# NOTE: Access token required for GitLab:
# https://docs.gitlab.com/user/project/settings/project_access_tokens/#bot-users-for-projects
# Must be stored in environment variable 'GITLAB_PROJECT_ACCESS_TOKEN'.

# API timeout, time limit for requests to GitLab's REST API
api_timeout = 10

# Name used to refer to your bot instance - see comment for github.app_name config
bot_name = MY-bot

# The base URL of your GitLab instance
instance_url = https://gitlab.com


[bot_control]
# which GH accounts have the permission to send commands to the bot
Expand Down
87 changes: 87 additions & 0 deletions connections/gitlab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# This file is part of the EESSI build-and-deploy bot,
# see https://github.com/EESSI/eessi-bot-software-layer
#
# The bot helps with requests to add software installations to the
# EESSI software layer, see https://github.com/EESSI/software-layer
#
# author: Sondre Bergsvaag Risanger (@sondrebr)
#
# license: GPLv2
#

# Standard library imports
import os

# Third party imports (anything installed into the local Python environment)
import gitlab

# Local application imports (anything from EESSI/eessi-bot-software-layer)
from tools import config, logging


_gl = None


def verify_connection(gl):
"""
Verifies connection to GitLab. Exits if verification fails.

Args:
Instance of gitlab.Gitlab (from python-gitlab)

Returns:
None (implicit)
"""
try:
# auth tests the instance's credentials by retrieving the access token user
gl.auth()
if type(gl.user) is not gl._objects.CurrentUser:
raise Exception("'user' attribute of Gitlab class instance is not of type 'CurrentUser'.")
except Exception as err:
logging.error(f"Failed to verify GitLab connection: {err}")


def connect():
"""
Creates a gitlab.Gitlab instance (from python-gitlab), then verifies the connection to GitLab.

Args:
No arguments

Returns:
None (implicit)
"""
global _gl
cfg = config.read_config()
gitlab_cfg = cfg[config.SECTION_GITLAB]
timeout = int(gitlab_cfg.get(config.GITLAB_SETTING_API_TIMEOUT, 10))
url = gitlab_cfg.get(config.GITLAB_SETTING_INSTANCE_URL)

access_token = os.getenv('GITLAB_PROJECT_ACCESS_TOKEN')
if access_token is None:
logging.error("GitLab token is not available via $GITLAB_PROJECT_ACCESS_TOKEN!")
else:
del os.environ['GITLAB_PROJECT_ACCESS_TOKEN']
Comment thread
sondrebr marked this conversation as resolved.

_gl = gitlab.Gitlab(url, access_token)
_gl.timeout = timeout
_gl.retry_transient_errors = True
verify_connection(_gl)


def get_instance():
"""
Returns a gitlab.Gitlab instance. Creates an instance if one does not exist,
otherwise verifies the existing instance.

Args:
No arguments

Returns:
Instance of gitlab.Gitlab (from python-gitlab)
"""
if not _gl:
connect()
else:
verify_connection(_gl)
return _gl
41 changes: 34 additions & 7 deletions eessi_bot_event_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
from tools.args import event_handler_parse
from tools.commands import EESSIBotCommand, EESSIBotCommandError, \
contains_any_bot_command, get_bot_command
from tools.event_info import create_event_info_instance
from tools.git import connect_to_git_hosting_platform, get_git_hosting_platform
from tools.permissions import check_command_permission
from tools.pr_comments import ChatLevels, create_comment

Expand Down Expand Up @@ -95,12 +97,18 @@
config.DOWNLOAD_PR_COMMENTS_SETTING_PR_DIFF_TIP], # required
config.SECTION_EVENT_HANDLER: [
config.EVENT_HANDLER_SETTING_LOG_PATH], # required
config.SECTION_GIT: [
config.GIT_SETTING_HOSTING_PLATFORM], # required
config.SECTION_GITHUB: [
config.GITHUB_SETTING_API_TIMEOUT, # required
config.GITHUB_SETTING_APP_ID, # required
config.GITHUB_SETTING_APP_NAME, # required
config.GITHUB_SETTING_INSTALLATION_ID, # required
config.GITHUB_SETTING_PRIVATE_KEY], # required
config.GITHUB_SETTING_API_TIMEOUT, # required for github
config.GITHUB_SETTING_APP_ID, # required for github
config.GITHUB_SETTING_APP_NAME, # required for github
config.GITHUB_SETTING_INSTALLATION_ID, # required for github
config.GITHUB_SETTING_PRIVATE_KEY], # required for github
config.SECTION_GITLAB: [
config.GITLAB_SETTING_API_TIMEOUT, # required for gitlab
config.GITLAB_SETTING_BOT_NAME, # required for gitlab
config.GITLAB_SETTING_INSTANCE_URL], # required for gitlab
# the poll interval setting is required for the alternative job handover
# protocol (delayed_begin)
config.SECTION_JOB_MANAGER: [
Expand Down Expand Up @@ -133,7 +141,8 @@ def __init__(self, *args, **kwargs):
EESSIBotSoftwareLayer constructor. Calls constructor of PyGHee and
initializes some configuration settings.
"""
super(EESSIBotSoftwareLayer, self).__init__(*args, **kwargs)
event_source = get_git_hosting_platform()
super(EESSIBotSoftwareLayer, self).__init__(event_source, *args, **kwargs)

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

def handle_event(self, event_info, log_file=None):
"""
Override of PyGHee's handle_event method.
Create EventInfo instance using event_info,
then pass that to PyGHee's handle_event method.
Comment thread
sondrebr marked this conversation as resolved.

Args:
event_info (dict): event received by event_handler
log_file (string): path to log messages to

Returns:
None (implicit)
"""
event_info_object = create_event_info_instance(event_info)
super().handle_event(event_info_object, log_file)

def handle_issue_comment_event(self, event_info, log_file=None):
"""
Handle events of type issue_comment. Main action is to parse new issue
Expand Down Expand Up @@ -833,7 +858,9 @@ def main():
else:
print("Configuration check: FAILED")
sys.exit(1)
github.connect()

# Verify that the event handler is able to connect to the Git hosting platform
connect_to_git_hosting_platform()

if opts.file:
app = create_app(klass=EESSIBotSoftwareLayer)
Expand Down
5 changes: 4 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
# author: Bob Droege (@bedroge)
# author: Kenneth Hoste (@boegel)
# author: Thomas Roeblitz (@trz42)
# author: Sondre Bergsvaag Risanger (@sondrebr)
#
# license: GPLv2
#
PyGithub
python-gitlab==6.5.0;python_version=="3.9" # Last version with Python 3.9 support
python-gitlab==8.3.0;python_version>="3.10" # Most recent version on 2026-05-04
Waitress>=3.0.1 # required to fix vulnerabilities detected by scorecards
cryptography>=44.0.1 # required to fix vulnerabilities detected by scorecards
PyGHee>=0.0.3
PyGHee @ git+https://github.com/boegel/PyGHee.git@c5e10632a45db5ca94f5cbf87ac7a90a2064e8fd # Pin commit with GL support
retry
13 changes: 13 additions & 0 deletions tools/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
# (none yet)

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

# define configuration constants
Expand Down Expand Up @@ -95,13 +96,21 @@
FINISHED_JOB_COMMENTS_SETTING_JOB_RESULT_UNKNOWN_FMT = 'job_result_unknown_fmt'
FINISHED_JOB_COMMENTS_SETTING_JOB_TEST_UNKNOWN_FMT = 'job_test_unknown_fmt'

SECTION_GIT = 'git'
GIT_SETTING_HOSTING_PLATFORM = 'hosting_platform'

SECTION_GITHUB = 'github'
GITHUB_SETTING_API_TIMEOUT = 'api_timeout'
GITHUB_SETTING_APP_ID = 'app_id'
GITHUB_SETTING_APP_NAME = 'app_name'
GITHUB_SETTING_INSTALLATION_ID = 'installation_id'
GITHUB_SETTING_PRIVATE_KEY = 'private_key'

SECTION_GITLAB = 'gitlab'
GITLAB_SETTING_API_TIMEOUT = 'api_timeout'
GITLAB_SETTING_BOT_NAME = 'bot_name'
GITLAB_SETTING_INSTANCE_URL = 'instance_url'

SECTION_JOB_MANAGER = 'job_manager'
JOB_MANAGER_SETTING_LOG_PATH = 'log_path'
JOB_MANAGER_SETTING_JOB_IDS_DIR = 'job_ids_dir'
Expand Down Expand Up @@ -207,9 +216,13 @@ def check_cfg_settings(req_settings, path="app.cfg"):
"""
# TODO argument path is not being used
cfg = read_config()
git_host = get_git_hosting_platform(cfg)
# iterate over keys in req_settings which correspond to sections ([name])
# in the configuration file (.ini format)
for section in req_settings.keys():
# Skip checking the GitLab section if the bot is configured for GitHub and vice versa
if git_host and (section in SUPPORTED_GIT_HOSTS) and (section != git_host):
continue
Comment thread
sondrebr marked this conversation as resolved.
if section not in cfg:
error(f'Missing section "{section}" in configuration file {path}.')
# iterate over list elements required for the current section
Expand Down
Loading
Loading