Skip to content

Commit

Permalink
Pass required information to cov_to_lint.py
Browse files Browse the repository at this point in the history
Now that we run linters for a baseline on `rev1` in a temporary clone
of the repository, `cov_to_lint.py` needs to find the pre-generated
coverage files. For that, we pass the original repository root path and
the revision being linted as environment variables.
  • Loading branch information
akaihola committed Jan 16, 2023
1 parent b585481 commit be037eb
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 9 deletions.
54 changes: 47 additions & 7 deletions src/darker/linting.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"""

import logging
import os
import shlex
from collections import defaultdict
from contextlib import contextmanager
Expand All @@ -36,6 +37,7 @@
git_clone_local,
git_get_content_at_revision,
git_get_root,
git_rev_parse,
shlex_join,
)
from darker.highlighting import colorize
Expand Down Expand Up @@ -119,6 +121,24 @@ def get(self, new_location: MessageLocation) -> MessageLocation:
return NO_MESSAGE_LOCATION


def make_linter_env(root: Path, revision: str) -> Dict[str, str]:
"""Populate environment variables for running linters
:param root: The path to the root of the Git repository
:param revision: The commit hash of the Git revision being linted, or ``"WORKTREE"``
if the working tree is being linted
:return: The environment variables dictionary to pass to the linter
"""
return {
**os.environ,
"DARKER_LINT_ORIG_REPO": str(root),
"DARKER_LINT_REV_COMMIT": (
"WORKTREE" if revision == "WORKTREE" else revision[:7]
),
}


def _strict_nonneg_int(text: str) -> int:
"""Strict parsing of strings to non-negative integers
Expand Down Expand Up @@ -229,12 +249,14 @@ def _check_linter_output(
cmdline: Union[str, List[str]],
root: Path,
paths: Collection[Path],
env: Dict[str, str],
) -> Generator[IO[str], None, None]:
"""Run a linter as a subprocess and return its standard output stream
:param cmdline: The command line for running the linter
:param root: The common root of all files to lint
:param paths: Paths of files to check, relative to ``root``
:param env: Environment variables to pass to the linter
:return: The standard output stream of the linter subprocess
"""
Expand All @@ -249,6 +271,7 @@ def _check_linter_output(
stdout=PIPE,
encoding="utf-8",
cwd=root,
env=env,
) as linter_process:
# condition needed for MyPy (see https://stackoverflow.com/q/57350490/15770)
if linter_process.stdout is None:
Expand All @@ -260,13 +283,14 @@ def run_linter( # pylint: disable=too-many-locals
cmdline: Union[str, List[str]],
root: Path,
paths: Collection[Path],
env: Dict[str, str],
) -> Dict[MessageLocation, LinterMessage]:
"""Run the given linter and return linting errors falling on changed lines
:param cmdline: The command line for running the linter
:param root: The common root of all files to lint
:param paths: Paths of files to check, relative to ``root``
:param revrange: The Git revision rango to compare
:param env: Environment variables to pass to the linter
:return: The number of modified lines with linting errors from this linter
"""
Expand All @@ -278,7 +302,7 @@ def run_linter( # pylint: disable=too-many-locals
else:
linter = cmdline[0]
cmdline_str = shlex_join(cmdline)
with _check_linter_output(cmdline, root, paths) as linter_stdout:
with _check_linter_output(cmdline, root, paths, env) as linter_stdout:
for line in linter_stdout:
(location, message) = _parse_linter_line(linter, line, root)
if location is NO_MESSAGE_LOCATION or location.path in missing_files:
Expand Down Expand Up @@ -334,6 +358,7 @@ def run_linters(
linter_cmdlines,
root,
paths,
make_linter_env(root, "WORKTREE"),
)
return _print_new_linter_messages(
baseline={},
Expand All @@ -343,9 +368,17 @@ def run_linters(
)
git_paths = {(root / path).relative_to(git_root) for path in paths}
baseline = _get_messages_from_linters_for_baseline(
linter_cmdlines, git_root, git_paths, revrange.rev1
linter_cmdlines,
git_root,
git_paths,
revrange.rev1,
)
messages = _get_messages_from_linters(
linter_cmdlines,
git_root,
git_paths,
make_linter_env(git_root, "WORKTREE"),
)
messages = _get_messages_from_linters(linter_cmdlines, git_root, git_paths)
files_with_messages = {location.path for location in messages}
diff_line_mapping = _create_line_mapping(git_root, files_with_messages, revrange)
return _print_new_linter_messages(baseline, messages, diff_line_mapping, use_color)
Expand All @@ -355,19 +388,20 @@ def _get_messages_from_linters(
linter_cmdlines: Iterable[Union[str, List[str]]],
root: Path,
paths: Collection[Path],
env: Dict[str, str],
) -> Dict[MessageLocation, List[LinterMessage]]:
"""Run given linters for the given directory and return linting errors
:param linter_cmdlines: The command lines for running the linters
:param root: The common root of all files to lint
:param paths: Paths of files to check, relative to ``root``
:param revrange: The Git revision rango to compare
:param env: The environment variables to pass to the linter
:return: Linter messages
"""
result = defaultdict(list)
for cmdline in linter_cmdlines:
for message_location, message in run_linter(cmdline, root, paths).items():
for message_location, message in run_linter(cmdline, root, paths, env).items():
result[message_location].append(message)
return result

Expand Down Expand Up @@ -429,7 +463,13 @@ def _get_messages_from_linters_for_baseline(
"""
with TemporaryDirectory() as tmp_path:
clone_root = git_clone_local(root, revision, Path(tmp_path))
result = _get_messages_from_linters(linter_cmdlines, clone_root, paths)
rev1_commit = git_rev_parse(revision, root)
result = _get_messages_from_linters(
linter_cmdlines,
clone_root,
paths,
make_linter_env(root, rev1_commit),
)
fix_py37_win_tempdir_permissions(tmp_path)
return result

Expand Down
12 changes: 10 additions & 2 deletions src/darker/tests/test_linting.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@

from darker import linting
from darker.git import WORKTREE, RevisionRange
from darker.linting import DiffLineMapping, LinterMessage, MessageLocation
from darker.linting import (
DiffLineMapping,
LinterMessage,
MessageLocation,
make_linter_env,
)
from darker.tests.helpers import raises_if_exception
from darker.utils import WINDOWS

Expand Down Expand Up @@ -169,7 +174,10 @@ def test_require_rev2_worktree(rev2, expect):
def test_check_linter_output(tmp_path, cmdline, expect):
"""``_check_linter_output()`` runs linter and returns the stdout stream"""
with linting._check_linter_output(
cmdline, tmp_path, {Path("first.py"), Path("the 2nd.py")}
cmdline,
tmp_path,
{Path("first.py"), Path("the 2nd.py")},
make_linter_env(tmp_path, "WORKTREE"),
) as stdout:
lines = list(stdout)

Expand Down

0 comments on commit be037eb

Please sign in to comment.