Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extra testing with read-only venv or cwd #4529

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions src/ansiblelint/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ def expand_to_normalized_paths(
config[paths_var] = normalized_paths


def load_config(config_file: str | None) -> tuple[dict[Any, Any], str | None]:
def load_config(
config_file: str | None = None, project_path: str | None = None
) -> tuple[dict[Any, Any], str | None]:
"""Load configuration from disk."""
config_path = None

Expand All @@ -74,7 +76,7 @@ def load_config(config_file: str | None) -> tuple[dict[Any, Any], str | None]:
if not os.path.exists(config_path):
_logger.error("Config file not found '%s'", config_path)
sys.exit(RC.INVALID_CONFIG)
config_path = config_path or get_config_path()
config_path = config_path or get_config_path(None, project_path=project_path)
if not config_path or not os.path.exists(config_path):
# a missing default config file should not trigger an error
return {}, None
Expand All @@ -100,7 +102,9 @@ def load_config(config_file: str | None) -> tuple[dict[Any, Any], str | None]:
return config, config_path


def get_config_path(config_file: str | None = None) -> str | None:
def get_config_path(
config_file: str | None = None, project_path: str | None = None
) -> str | None:
"""Return local config file."""
if config_file:
project_filenames = [config_file]
Expand All @@ -112,7 +116,7 @@ def get_config_path(config_file: str | None = None) -> str | None:
".config/ansible-lint.yml",
".config/ansible-lint.yaml",
]
parent = tail = os.getcwd()
parent = tail = project_path or os.getcwd()
while tail:
for project_filename in project_filenames:
filename = os.path.abspath(os.path.join(parent, project_filename))
Expand Down Expand Up @@ -460,8 +464,8 @@ def get_cli_parser() -> argparse.ArgumentParser:
parser.add_argument(
"--offline",
dest="offline",
action="store_const",
const=True,
action=argparse.BooleanOptionalAction,
default=False,
help="Disable installation of requirements.yml and schema refreshing",
)
parser.add_argument(
Expand Down Expand Up @@ -595,7 +599,9 @@ def get_config(arguments: list[str]) -> Options:
)

# save info about custom config file, as options.config_file may be modified by merge_config
file_config, options.config_file = load_config(options.config_file)
file_config, options.config_file = load_config(
options.config_file, project_path=options.project_dir
)
config = merge_config(file_config, options)

options.rulesdirs = get_rules_dirs(
Expand Down
31 changes: 31 additions & 0 deletions test/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import tempfile
import time
from http.client import RemoteDisconnected
from os.path import abspath
from pathlib import Path

import pytest
Expand Down Expand Up @@ -155,3 +156,33 @@ def test_broken_ansible_cfg() -> None:
"Invalid type for configuration option setting: CACHE_PLUGIN_TIMEOUT"
in proc.stderr
)


def test_ro_venv() -> None:
"""Tests behavior when the virtual environment is read-only."""
tox_work_dir = os.environ.get("TOX_WORK_DIR", ".tox")
venv_path = f"{tox_work_dir}/ro"
commands = [
f"mkdir -p {venv_path}",
f"chmod -R a+w {venv_path}",
f"python -m venv --symlinks {venv_path}",
f"{venv_path}/bin/python -m pip install -q -e .",
f"chmod -R a-w {venv_path}",
# running with a ro venv and default cwd
f"{venv_path}/bin/ansible-lint --version",
# running from a read-only cwd:
f"cd / && {abspath(venv_path)}/bin/ansible-lint --version", # noqa: PTH100
# running with a ro venv and a custom project path in forced non-online mode, so it will need to install requirements
f"{venv_path}/bin/ansible-lint -vv --no-offline --project-dir ./examples/reqs_v2/ ./examples/reqs_v2/",
]
for cmd in commands:
result = subprocess.run(
cmd,
check=False,
shell=True,
text=True,
capture_output=True,
)
assert result.returncode == 0, (
f"Got {result.returncode} running {cmd}\n\tstderr: {result.stderr}\n\tstdout: {result.stdout}"
)
Loading