Coverage for src/mafw/devtools/gitlab/api.py: 100%
34 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-26 09:13 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-26 09:13 +0000
1# Copyright 2026 European Union
2# Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
3# SPDX-License-Identifier: EUPL-1.2
4"""
5GitLab API configuration and authentication helpers.
7:author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
8"""
10from __future__ import annotations
12import os
13from collections.abc import MutableMapping
14from dataclasses import dataclass
15from typing import Literal
18@dataclass(frozen=True, slots=True)
19class GitlabAPIConfiguration:
20 """Configuration needed to communicate with the GitLab API.
22 :param api_url: Base GitLab API v4 URL.
23 :type api_url: str
24 :param on_ci: Whether the process runs on GitLab CI.
25 :type on_ci: bool
26 :param project_id: GitLab project numeric ID.
27 :type project_id: int
28 :param token: Authentication token value.
29 :type token: str
30 :param token_type: Token kind used for authentication.
31 :type token_type: Literal['job_token', 'api_token']
32 """
34 api_url: str
35 on_ci: bool
36 project_id: int
37 token: str
38 token_type: Literal['job_token', 'api_token']
41def build_gitlab_api_configuration(
42 api_url: str | None, project_id: int | None, token: str | None
43) -> GitlabAPIConfiguration:
44 """Build a GitLab API configuration from provided values and environment context.
46 :param api_url: Optional override for the GitLab API URL.
47 :type api_url: str | None
48 :param project_id: Optional override for the GitLab project ID.
49 :type project_id: int | None
50 :param token: Optional override for the authentication token.
51 :type token: str | None
52 :return: The validated GitLab API configuration.
53 :rtype: gitlab.GitlabAPIConfiguration
54 :raises ValueError: If any required configuration value is missing.
55 """
56 if api_url is None:
57 api_url = os.environ.get('CI_API_V4_URL')
58 if project_id is None:
59 project_id_env = os.environ.get('CI_PROJECT_ID')
60 project_id = int(project_id_env) if project_id_env else None
61 if token is None:
62 token = os.environ.get('CI_JOB_TOKEN')
64 missing: list[str] = []
65 if not api_url:
66 missing.append('api_url')
67 if project_id is None:
68 missing.append('project_id')
69 if not token:
70 missing.append('token')
72 if missing or api_url is None or project_id is None or token is None:
73 raise ValueError(f'Missing GitLab configuration values: {", ".join(missing)}')
75 return GitlabAPIConfiguration(
76 api_url=api_url,
77 on_ci=bool(os.environ.get('CI')),
78 project_id=project_id,
79 token=token,
80 token_type='job_token' if bool(os.environ.get('CI')) else 'api_token',
81 )
84def build_gitlab_auth_headers(api_config: GitlabAPIConfiguration) -> MutableMapping[str, str | bytes]:
85 """Build authentication headers for GitLab API requests.
87 :param api_config: The GitLab API configuration.
88 :type api_config: gitlab.GitlabAPIConfiguration
89 :return: A mutable mapping of HTTP headers.
90 :rtype: MutableMapping[str, str | bytes]
91 """
92 if api_config.on_ci:
93 return {'JOB-TOKEN': api_config.token}
94 return {'PRIVATE-TOKEN': api_config.token}