""" Some test cases are run in-process to intercept requests to gitlab.com and example servers. """ import copy import json import pytest import responses import yaml from gitlab import __version__, config from gitlab.const import DEFAULT_URL PRIVATE_TOKEN = "glpat-abc123" CI_JOB_TOKEN = "ci-job-token" CI_SERVER_URL = "https://gitlab.example.com" def test_main_entrypoint(script_runner, gitlab_config): ret = script_runner.run("python", "-m", "gitlab", "--config-file", gitlab_config) assert ret.returncode == 2 def test_version(script_runner): ret = script_runner.run("gitlab", "--version") assert ret.stdout.strip() == __version__ def test_config_error_with_help_prints_help(script_runner): ret = script_runner.run("gitlab", "-c", "invalid-file", "--help") assert ret.stdout.startswith("usage:") assert ret.returncode == 0 def test_global_help_prints_resources_vertically(script_runner): ret = script_runner.run("gitlab", "--help") assert """resource:\n application\n application-appearance\n""" in ret.stdout assert ret.returncode == 0 def test_resource_help_prints_actions_vertically(script_runner): ret = script_runner.run("gitlab", "project", "--help") assert """action:\n list\n get""" in ret.stdout assert ret.returncode == 0 @pytest.mark.script_launch_mode("inprocess") @responses.activate def test_defaults_to_gitlab_com(script_runner, resp_get_project, monkeypatch): responses.add(**resp_get_project) monkeypatch.setattr(config, "_DEFAULT_FILES", []) ret = script_runner.run("gitlab", "project", "get", "--id", "1") assert ret.success assert "id: 1" in ret.stdout @pytest.mark.script_launch_mode("inprocess") @responses.activate def test_uses_ci_server_url(monkeypatch, script_runner, resp_get_project): monkeypatch.setenv("CI_SERVER_URL", CI_SERVER_URL) monkeypatch.setattr(config, "_DEFAULT_FILES", []) resp_get_project_in_ci = copy.deepcopy(resp_get_project) resp_get_project_in_ci.update(url=f"{CI_SERVER_URL}/api/v4/projects/1") responses.add(**resp_get_project_in_ci) ret = script_runner.run("gitlab", "project", "get", "--id", "1") assert ret.success @pytest.mark.script_launch_mode("inprocess") @responses.activate def test_uses_ci_job_token(monkeypatch, script_runner, resp_get_project): monkeypatch.setenv("CI_JOB_TOKEN", CI_JOB_TOKEN) monkeypatch.setattr(config, "_DEFAULT_FILES", []) resp_get_project_in_ci = copy.deepcopy(resp_get_project) resp_get_project_in_ci.update( match=[responses.matchers.header_matcher({"JOB-TOKEN": CI_JOB_TOKEN})], ) responses.add(**resp_get_project_in_ci) ret = script_runner.run("gitlab", "project", "get", "--id", "1") assert ret.success @pytest.mark.script_launch_mode("inprocess") @responses.activate def test_private_token_overrides_job_token( monkeypatch, script_runner, resp_get_project ): monkeypatch.setenv("GITLAB_PRIVATE_TOKEN", PRIVATE_TOKEN) monkeypatch.setenv("CI_JOB_TOKEN", CI_JOB_TOKEN) resp_get_project_with_token = copy.deepcopy(resp_get_project) resp_get_project_with_token.update( match=[responses.matchers.header_matcher({"PRIVATE-TOKEN": PRIVATE_TOKEN})], ) # CLI first calls .auth() when private token is present resp_auth_with_token = copy.deepcopy(resp_get_project_with_token) resp_auth_with_token.update(url=f"{DEFAULT_URL}/api/v4/user") resp_auth_with_token["json"].update(username="user", web_url=f"{DEFAULT_URL}/user") responses.add(**resp_get_project_with_token) responses.add(**resp_auth_with_token) ret = script_runner.run("gitlab", "project", "get", "--id", "1") assert ret.success def test_env_config_missing_file_raises(script_runner, monkeypatch): monkeypatch.setenv("PYTHON_GITLAB_CFG", "non-existent") ret = script_runner.run("gitlab", "project", "list") assert not ret.success assert ret.stderr.startswith("Cannot read config from PYTHON_GITLAB_CFG") def test_arg_config_missing_file_raises(script_runner): ret = script_runner.run( "gitlab", "--config-file", "non-existent", "project", "list" ) assert not ret.success assert ret.stderr.startswith("Cannot read config from file") def test_invalid_config(script_runner): ret = script_runner.run("gitlab", "--gitlab", "invalid") assert not ret.success assert not ret.stdout def test_invalid_config_prints_help(script_runner): ret = script_runner.run("gitlab", "--gitlab", "invalid", "--help") assert ret.success assert ret.stdout def test_invalid_api_version(script_runner, monkeypatch, fixture_dir): monkeypatch.setenv("PYTHON_GITLAB_CFG", str(fixture_dir / "invalid_version.cfg")) ret = script_runner.run("gitlab", "--gitlab", "test", "project", "list") assert not ret.success assert ret.stderr.startswith("Unsupported API version:") def test_invalid_auth_config(script_runner, monkeypatch, fixture_dir): monkeypatch.setenv("PYTHON_GITLAB_CFG", str(fixture_dir / "invalid_auth.cfg")) ret = script_runner.run("gitlab", "--gitlab", "test", "project", "list") assert not ret.success assert "401" in ret.stderr format_matrix = [ ("json", json.loads), ("yaml", yaml.safe_load), ] @pytest.mark.parametrize("format,loader", format_matrix) def test_cli_display(gitlab_cli, project, format, loader): cmd = ["-o", format, "project", "get", "--id", project.id] ret = gitlab_cli(cmd) assert ret.success content = loader(ret.stdout.strip()) assert content["id"] == project.id @pytest.mark.parametrize("format,loader", format_matrix) def test_cli_fields_in_list(gitlab_cli, project_file, format, loader): cmd = [ "-o", format, "--fields", "default_branch", "project", "list", ] ret = gitlab_cli(cmd) assert ret.success content = loader(ret.stdout.strip()) assert ["default_branch" in item for item in content]