summaryrefslogtreecommitdiff
path: root/gitlab
diff options
context:
space:
mode:
authorNejc Habjan <hab.nejc@gmail.com>2021-12-12 19:19:45 +0100
committerNejc Habjan <hab.nejc@gmail.com>2021-12-13 01:11:15 +0100
commit92a893b8e230718436582dcad96175685425b1df (patch)
treeabfa0a78a5bb5429cd0a7bbe28e58e665737e511 /gitlab
parentaf33affa4888fa83c31557ae99d7bbd877e9a605 (diff)
downloadgitlab-feat/cli-without-config-file.tar.gz
feat(cli): do not require config file to run CLIfeat/cli-without-config-file
BREAKING CHANGE: A config file is no longer needed to run the CLI. python-gitlab will default to https://gitlab.com with no authentication if there is no config file provided. python-gitlab will now also only look for configuration in the provided PYTHON_GITLAB_CFG path, instead of merging it with user- and system-wide config files. If the environment variable is defined and the file cannot be opened, python-gitlab will now explicitly fail.
Diffstat (limited to 'gitlab')
-rw-r--r--gitlab/config.py154
1 files changed, 94 insertions, 60 deletions
diff --git a/gitlab/config.py b/gitlab/config.py
index 6c75d0a..154f063 100644
--- a/gitlab/config.py
+++ b/gitlab/config.py
@@ -20,20 +20,14 @@ import os
import shlex
import subprocess
from os.path import expanduser, expandvars
+from pathlib import Path
from typing import List, Optional, Union
-from gitlab.const import USER_AGENT
+from gitlab.const import DEFAULT_URL, USER_AGENT
-
-def _env_config() -> List[str]:
- if "PYTHON_GITLAB_CFG" in os.environ:
- return [os.environ["PYTHON_GITLAB_CFG"]]
- return []
-
-
-_DEFAULT_FILES: List[str] = _env_config() + [
+_DEFAULT_FILES: List[str] = [
"/etc/python-gitlab.cfg",
- os.path.expanduser("~/.python-gitlab.cfg"),
+ str(Path.home() / ".python-gitlab.cfg"),
]
HELPER_PREFIX = "helper:"
@@ -41,6 +35,52 @@ HELPER_PREFIX = "helper:"
HELPER_ATTRIBUTES = ["job_token", "http_password", "private_token", "oauth_token"]
+def _resolve_file(filepath: Union[Path, str]) -> str:
+ resolved = Path(filepath).resolve(strict=True)
+ return str(resolved)
+
+
+def _get_config_files(
+ config_files: Optional[List[str]] = None,
+) -> Union[str, List[str]]:
+ """
+ Return resolved path(s) to config files if they exist, with precedence:
+ 1. Files passed in config_files
+ 2. File defined in PYTHON_GITLAB_CFG
+ 3. User- and system-wide config files
+ """
+ resolved_files = []
+
+ if config_files:
+ for config_file in config_files:
+ try:
+ resolved = _resolve_file(config_file)
+ except OSError as e:
+ raise GitlabConfigMissingError(f"Cannot read config from file: {e}")
+ resolved_files.append(resolved)
+
+ return resolved_files
+
+ try:
+ env_config = os.environ["PYTHON_GITLAB_CFG"]
+ return _resolve_file(env_config)
+ except KeyError:
+ pass
+ except OSError as e:
+ raise GitlabConfigMissingError(
+ f"Cannot read config from PYTHON_GITLAB_CFG: {e}"
+ )
+
+ for config_file in _DEFAULT_FILES:
+ try:
+ resolved = _resolve_file(config_file)
+ except OSError:
+ continue
+ resolved_files.append(resolved)
+
+ return resolved_files
+
+
class ConfigError(Exception):
pass
@@ -66,155 +106,149 @@ class GitlabConfigParser(object):
self, gitlab_id: Optional[str] = None, config_files: Optional[List[str]] = None
) -> None:
self.gitlab_id = gitlab_id
- _files = config_files or _DEFAULT_FILES
- file_exist = False
- for file in _files:
- if os.path.exists(file):
- file_exist = True
- if not file_exist:
- raise GitlabConfigMissingError(
- "Config file not found. \nPlease create one in "
- "one of the following locations: {} \nor "
- "specify a config file using the '-c' parameter.".format(
- ", ".join(_DEFAULT_FILES)
- )
- )
+ self.http_username: Optional[str] = None
+ self.http_password: Optional[str] = None
+ self.job_token: Optional[str] = None
+ self.oauth_token: Optional[str] = None
+ self.private_token: Optional[str] = None
+
+ self.api_version: str = "4"
+ self.order_by: Optional[str] = None
+ self.pagination: Optional[str] = None
+ self.per_page: Optional[int] = None
+ self.retry_transient_errors: bool = False
+ self.ssl_verify: Union[bool, str] = True
+ self.timeout: int = 60
+ self.url: str = DEFAULT_URL
+ self.user_agent: str = USER_AGENT
- self._config = configparser.ConfigParser()
- self._config.read(_files)
+ self._files = _get_config_files(config_files)
+ if self._files:
+ self._parse_config()
+
+ def _parse_config(self) -> None:
+ _config = configparser.ConfigParser()
+ _config.read(self._files)
if self.gitlab_id is None:
try:
- self.gitlab_id = self._config.get("global", "default")
+ self.gitlab_id = _config.get("global", "default")
except Exception as e:
raise GitlabIDError(
"Impossible to get the gitlab id (not specified in config file)"
) from e
try:
- self.url = self._config.get(self.gitlab_id, "url")
+ self.url = _config.get(self.gitlab_id, "url")
except Exception as e:
raise GitlabDataError(
"Impossible to get gitlab details from "
f"configuration ({self.gitlab_id})"
) from e
- self.ssl_verify: Union[bool, str] = True
try:
- self.ssl_verify = self._config.getboolean("global", "ssl_verify")
+ self.ssl_verify = _config.getboolean("global", "ssl_verify")
except ValueError:
# Value Error means the option exists but isn't a boolean.
# Get as a string instead as it should then be a local path to a
# CA bundle.
try:
- self.ssl_verify = self._config.get("global", "ssl_verify")
+ self.ssl_verify = _config.get("global", "ssl_verify")
except Exception:
pass
except Exception:
pass
try:
- self.ssl_verify = self._config.getboolean(self.gitlab_id, "ssl_verify")
+ self.ssl_verify = _config.getboolean(self.gitlab_id, "ssl_verify")
except ValueError:
# Value Error means the option exists but isn't a boolean.
# Get as a string instead as it should then be a local path to a
# CA bundle.
try:
- self.ssl_verify = self._config.get(self.gitlab_id, "ssl_verify")
+ self.ssl_verify = _config.get(self.gitlab_id, "ssl_verify")
except Exception:
pass
except Exception:
pass
- self.timeout = 60
try:
- self.timeout = self._config.getint("global", "timeout")
+ self.timeout = _config.getint("global", "timeout")
except Exception:
pass
try:
- self.timeout = self._config.getint(self.gitlab_id, "timeout")
+ self.timeout = _config.getint(self.gitlab_id, "timeout")
except Exception:
pass
- self.private_token = None
try:
- self.private_token = self._config.get(self.gitlab_id, "private_token")
+ self.private_token = _config.get(self.gitlab_id, "private_token")
except Exception:
pass
- self.oauth_token = None
try:
- self.oauth_token = self._config.get(self.gitlab_id, "oauth_token")
+ self.oauth_token = _config.get(self.gitlab_id, "oauth_token")
except Exception:
pass
- self.job_token = None
try:
- self.job_token = self._config.get(self.gitlab_id, "job_token")
+ self.job_token = _config.get(self.gitlab_id, "job_token")
except Exception:
pass
- self.http_username = None
- self.http_password = None
try:
- self.http_username = self._config.get(self.gitlab_id, "http_username")
- self.http_password = self._config.get(self.gitlab_id, "http_password")
+ self.http_username = _config.get(self.gitlab_id, "http_username")
+ self.http_password = _config.get(self.gitlab_id, "http_password")
except Exception:
pass
self._get_values_from_helper()
- self.api_version = "4"
try:
- self.api_version = self._config.get("global", "api_version")
+ self.api_version = _config.get("global", "api_version")
except Exception:
pass
try:
- self.api_version = self._config.get(self.gitlab_id, "api_version")
+ self.api_version = _config.get(self.gitlab_id, "api_version")
except Exception:
pass
if self.api_version not in ("4",):
raise GitlabDataError(f"Unsupported API version: {self.api_version}")
- self.per_page = None
for section in ["global", self.gitlab_id]:
try:
- self.per_page = self._config.getint(section, "per_page")
+ self.per_page = _config.getint(section, "per_page")
except Exception:
pass
if self.per_page is not None and not 0 <= self.per_page <= 100:
raise GitlabDataError(f"Unsupported per_page number: {self.per_page}")
- self.pagination = None
try:
- self.pagination = self._config.get(self.gitlab_id, "pagination")
+ self.pagination = _config.get(self.gitlab_id, "pagination")
except Exception:
pass
- self.order_by = None
try:
- self.order_by = self._config.get(self.gitlab_id, "order_by")
+ self.order_by = _config.get(self.gitlab_id, "order_by")
except Exception:
pass
- self.user_agent = USER_AGENT
try:
- self.user_agent = self._config.get("global", "user_agent")
+ self.user_agent = _config.get("global", "user_agent")
except Exception:
pass
try:
- self.user_agent = self._config.get(self.gitlab_id, "user_agent")
+ self.user_agent = _config.get(self.gitlab_id, "user_agent")
except Exception:
pass
- self.retry_transient_errors = False
try:
- self.retry_transient_errors = self._config.getboolean(
+ self.retry_transient_errors = _config.getboolean(
"global", "retry_transient_errors"
)
except Exception:
pass
try:
- self.retry_transient_errors = self._config.getboolean(
+ self.retry_transient_errors = _config.getboolean(
self.gitlab_id, "retry_transient_errors"
)
except Exception: