Skip to content

Commit

Permalink
Enable progressive mode
Browse files Browse the repository at this point in the history
Adds a new option --progressive that ease adoption of the linter as
it will only report failure if it detects an increase number
of violations since previous commit.
  • Loading branch information
ssbarnea committed Oct 2, 2020
1 parent 8ae9768 commit 2b0387c
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 1 deletion.
19 changes: 19 additions & 0 deletions README.rst
Expand Up @@ -94,6 +94,8 @@ The following is the output from ``ansible-lint --help``, providing an overview
-q quieter, although not silent output
-p parseable output in the format of pep8
--parseable-severity parseable output including severity of rule
--progressive Return success if it detects a reduction in number of violations compared with
previous git commit. This feature works only on git repository clones.
-r RULESDIR Specify custom rule directories. Add -R to keep using embedded rules from
/usr/local/lib/python3.8/site-packages/ansiblelint/rules
-R Keep default rules when using -r
Expand All @@ -111,6 +113,23 @@ The following is the output from ``ansible-lint --help``, providing an overview
-c CONFIG_FILE Specify configuration file to use. Defaults to ".ansible-lint"
--version show program's version number and exit
Progressive mode
----------------

In order to ease tool adoption, git users can enable the progressive mode using
``--progressive`` option. This makes the linter return a success even if
some failures are found, as long the total number of violations did not
increase since the previous commit.

As expected, this mode makes the linter run twice if it finds any violations.
The second run is performed against a temporary git working copy that contains
the previous commit. All the violations that were already present are removed
from the list and the final result is displayed.

The most notable benefit introduced by this mode it does not prevent merging
new code while allowing developer to address historical violation at his own
speed.

CI/CD
-----

Expand Down
54 changes: 53 additions & 1 deletion lib/ansiblelint/__main__.py
Expand Up @@ -24,7 +24,9 @@
import logging
import os
import pathlib
import subprocess
import sys
from contextlib import contextmanager
from typing import TYPE_CHECKING, List, Set, Type

from rich.markdown import Markdown
Expand Down Expand Up @@ -168,6 +170,35 @@ def main() -> int:
# Assure we do not print duplicates and the order is consistent
matches = sorted(set(matches))

mark_as_success = False
if matches and options.progressive:
_logger.info(
"Matches found, running again on previos revision in order to detect regressions")
with _previous_revision():
if not options.playbook:
# no args triggers auto-detection mode
playbooks = get_playbooks_and_roles(options=options)
else:
playbooks = sorted(set(options.playbook))

old_matches = list()
checked_files: Set[str] = set()
for playbook in playbooks:
runner = Runner(rules, playbook, options.tags,
options.skip_list, options.exclude_paths,
options.verbosity, checked_files)
old_matches.extend(runner.run())
# remove old matches from current list
if len(old_matches) > len(matches):
_logger.warning(
"Total violation(s) reducted from %s to %s since previous "
"commit, will mark result as success",
len(old_matches), len(matches))
mark_as_success = True
current_len = len(matches)
matches = set(matches) - set(old_matches)
_logger.warning("Removed %s previously known violation(s)", current_len - len(matches))

for match in matches:
print(formatter.format(match, options.colored))

Expand All @@ -177,12 +208,33 @@ def main() -> int:
for match in matches:
print(formatter.format(match))

if matches:
if matches and not mark_as_success:
return report_outcome(matches, options=options)
else:
return 0


@contextmanager
def _previous_revision():
"""Create or updates a temporary workdir containing the previous revious."""
worktree_dir = ".cache/old-rev"
try:
revision = subprocess.run(
["git", "rev-parse", "HEAD^1"],
check=True,
universal_newlines=True).stdout
p = pathlib.Path(worktree_dir)
p.mkdir(parents=True, exist_ok=True)
os.system(f"git worktree add -f {worktree_dir}")
os.chdir(worktree_dir)
os.system(f"git checkout {revision}")
yield
except Exception:
raise
else:
os.chdir("../..")


if __name__ == "__main__":
try:
sys.exit(main())
Expand Down
6 changes: 6 additions & 0 deletions lib/ansiblelint/cli.py
Expand Up @@ -111,6 +111,12 @@ def get_cli_parser() -> argparse.ArgumentParser:
default=False,
action='store_true',
help="parseable output including severity of rule")
parser.add_argument('--progressive', dest='progressive',
default=False,
action='store_true',
help="Return success if it detects a reduction in number"
" of violations compared with previous git commit. This "
"feature works only on git repository clones.")
parser.add_argument('-r', action=AbspathArgAction, dest='rulesdir',
default=[], type=Path,
help="Specify custom rule directories. Add -R "
Expand Down

0 comments on commit 2b0387c

Please sign in to comment.