Skip to content

Commit 13467c5

Browse files
committed
feat(cli): allow options from args and environment variables
1 parent ce4bc0d commit 13467c5

File tree

2 files changed

+141
-5
lines changed

2 files changed

+141
-5
lines changed

gitlab/cli.py

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import argparse
2121
import functools
22+
import os
2223
import re
2324
import sys
2425
from types import ModuleType
@@ -112,17 +113,22 @@ def _get_base_parser(add_help: bool = True) -> argparse.ArgumentParser:
112113
"-v",
113114
"--verbose",
114115
"--fancy",
115-
help="Verbose mode (legacy format only)",
116+
help="Verbose mode (legacy format only) [env var: GITLAB_VERBOSE]",
116117
action="store_true",
118+
default=os.getenv("GITLAB_VERBOSE"),
117119
)
118120
parser.add_argument(
119-
"-d", "--debug", help="Debug mode (display HTTP requests)", action="store_true"
121+
"-d",
122+
"--debug",
123+
help="Debug mode (display HTTP requests) [env var: GITLAB_DEBUG]",
124+
action="store_true",
125+
default=os.getenv("GITLAB_DEBUG"),
120126
)
121127
parser.add_argument(
122128
"-c",
123129
"--config-file",
124130
action="append",
125-
help="Configuration file to use. Can be used multiple times.",
131+
help="Configuration file to use. Can be used multiple times. [env var: PYTHON_GITLAB_CFG]",
126132
)
127133
parser.add_argument(
128134
"-g",
@@ -151,7 +157,86 @@ def _get_base_parser(add_help: bool = True) -> argparse.ArgumentParser:
151157
),
152158
required=False,
153159
)
154-
160+
# TODO: deduplicate everything by providing some data struct to loop over
161+
parser.add_argument(
162+
"--url",
163+
help=("GitLab server URL [env var: GITLAB_URL]"),
164+
required=False,
165+
default=os.getenv("GITLAB_URL"),
166+
)
167+
parser.add_argument(
168+
"--private-token",
169+
help=("GitLab private token [env var: GITLAB_PRIVATE_TOKEN]"),
170+
required=False,
171+
default=os.getenv("GITLAB_PRIVATE_TOKEN"),
172+
)
173+
parser.add_argument(
174+
"--oauth-token",
175+
help=("GitLab OAuth token [env var: GITLAB_OAUTH_TOKEN]"),
176+
required=False,
177+
default=os.getenv("GITLAB_OAUTH_TOKEN"),
178+
)
179+
parser.add_argument(
180+
"--job-token",
181+
help=(
182+
"GitLab CI job token. Explicitly providing this is usually not needed.\n"
183+
"[env var, only if explicitly overriding CI_JOB_TOKEN: GITLAB_JOB_TOKEN]"
184+
),
185+
required=False,
186+
default=os.getenv("GITLAB_JOB_TOKEN"),
187+
)
188+
parser.add_argument(
189+
"--ssl-verify",
190+
help=(
191+
"Whether SSL certificates should be validated. [env var: GITLAB_SSL_VERIFY]"
192+
),
193+
required=False,
194+
default=os.getenv("GITLAB_SSL_VERIFY"),
195+
)
196+
parser.add_argument(
197+
"--timeout",
198+
help=(
199+
"Timeout to use for requests to the GitLab server. [env var: GITLAB_TIMEOUT]"
200+
),
201+
required=False,
202+
default=os.getenv("GITLAB_TIMEOUT"),
203+
)
204+
parser.add_argument(
205+
"--api-version",
206+
help=("GitLab API version [env var: GITLAB_API_VERSION]"),
207+
required=False,
208+
default=os.getenv("GITLAB_API_VERSION"),
209+
)
210+
parser.add_argument(
211+
"--per-page",
212+
help=(
213+
"Number of entries to return per page in the response. [env var: GITLAB_PER_PAGE]"
214+
),
215+
required=False,
216+
default=os.getenv("GITLAB_PER_PAGE"),
217+
)
218+
parser.add_argument(
219+
"--pagination",
220+
help=(
221+
"Whether to use keyset or offset pagination [env var: GITLAB_PAGINATION]"
222+
),
223+
required=False,
224+
default=os.getenv("GITLAB_PAGINATION"),
225+
)
226+
parser.add_argument(
227+
"--order-by",
228+
help=("Set order_by globally [env var: GITLAB_ORDER_BY]"),
229+
required=False,
230+
default=os.getenv("GITLAB_ORDER_BY"),
231+
)
232+
parser.add_argument(
233+
"--user-agent",
234+
help=(
235+
"The user agent to send to GitLab with the HTTP request. [env var: GITLAB_USER_AGENT]"
236+
),
237+
required=False,
238+
default=os.getenv("GITLAB_USER_AGENT"),
239+
)
155240
return parser
156241

157242

@@ -248,7 +333,7 @@ def main() -> None:
248333
args_dict = {k: _parse_value(v) for k, v in args_dict.items() if v is not None}
249334

250335
try:
251-
gl = gitlab.Gitlab.from_config(gitlab_id, config_files)
336+
gl = gitlab.Gitlab.merge_config(options, gitlab_id, config_files)
252337
if gl.private_token or gl.oauth_token or gl.job_token:
253338
gl.auth()
254339
except Exception as e:

gitlab/client.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
"""Wrapper for the GitLab API."""
1818

19+
import os
1920
import time
21+
from argparse import Namespace
2022
from typing import Any, cast, Dict, List, Optional, Tuple, TYPE_CHECKING, Union
2123

2224
import requests
@@ -254,6 +256,55 @@ def from_config(
254256
retry_transient_errors=config.retry_transient_errors,
255257
)
256258

259+
@classmethod
260+
def merge_config(
261+
cls,
262+
options: Namespace,
263+
gitlab_id: Optional[str] = None,
264+
config_files: Optional[List[str]] = None,
265+
) -> "Gitlab":
266+
"""Create a Gitlab connection by merging configuration with
267+
the following precedence:
268+
269+
1. Explicitly provided CLI arguments,
270+
2. Environment variables,
271+
3. Configuration files:
272+
a. explicitly defined config files:
273+
i. via the `--config-file` CLI argument,
274+
ii. via the `PYTHON_GITLAB_CFG` environment variable,
275+
b. user-specific config file,
276+
c. system-level config file,
277+
4. Environment variables always present in CI (CI_SERVER_URL, CI_JOB_TOKEN).
278+
279+
Args:
280+
options list[str]: List of options provided via the CLI.
281+
gitlab_id (str): ID of the configuration section.
282+
config_files list[str]: List of paths to configuration files.
283+
Returns:
284+
(gitlab.Gitlab): A Gitlab connection.
285+
286+
Raises:
287+
gitlab.config.GitlabDataError: If the configuration is not correct.
288+
"""
289+
config = gitlab.config.GitlabConfigParser(
290+
gitlab_id=gitlab_id, config_files=config_files
291+
)
292+
return cls(
293+
url=options.url or config.url or os.getenv("CI_SERVER_URL"),
294+
private_token=options.private_token or config.private_token,
295+
oauth_token=options.oauth_token or config.oauth_token,
296+
job_token=options.job_token
297+
or config.job_token
298+
or os.getenv("CI_JOB_TOKEN"),
299+
ssl_verify=options.ssl_verify or config.ssl_verify,
300+
timeout=options.timeout or config.timeout,
301+
api_version=options.api_version or config.api_version,
302+
per_page=options.per_page or config.per_page,
303+
pagination=options.pagination or config.pagination,
304+
order_by=options.order_by or config.order_by,
305+
user_agent=options.user_agent or config.user_agent,
306+
)
307+
257308
def auth(self) -> None:
258309
"""Performs an authentication using private token.
259310

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy