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

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. 

6 

7:author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu) 

8""" 

9 

10from __future__ import annotations 

11 

12import os 

13from collections.abc import MutableMapping 

14from dataclasses import dataclass 

15from typing import Literal 

16 

17 

18@dataclass(frozen=True, slots=True) 

19class GitlabAPIConfiguration: 

20 """Configuration needed to communicate with the GitLab API. 

21 

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 """ 

33 

34 api_url: str 

35 on_ci: bool 

36 project_id: int 

37 token: str 

38 token_type: Literal['job_token', 'api_token'] 

39 

40 

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. 

45 

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') 

63 

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') 

71 

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)}') 

74 

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 ) 

82 

83 

84def build_gitlab_auth_headers(api_config: GitlabAPIConfiguration) -> MutableMapping[str, str | bytes]: 

85 """Build authentication headers for GitLab API requests. 

86 

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}