Skip to content

Commit

Permalink
[analyzer] gerrit output for parse subcommand
Browse files Browse the repository at this point in the history
Add gerrit output format for the parse subcommand

Test modifications:
  New unit test structure for the codechecker_common module.
  New gerrit format converter unit tests.
  • Loading branch information
Gyorgy Orban committed Nov 2, 2020
1 parent c4bab88 commit ac43204
Show file tree
Hide file tree
Showing 9 changed files with 460 additions and 33 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ CC_WEB = $(CURRENT_DIR)/web
CC_SERVER = $(CC_WEB)/server/
CC_CLIENT = $(CC_WEB)/client/
CC_ANALYZER = $(CURRENT_DIR)/analyzer
CC_COMMON = $(CURRENT_DIR)/codechecker_common

CC_TOOLS = $(CURRENT_DIR)/tools
CC_ANALYZER_TOOLS = $(CC_ANALYZER)/tools
Expand Down Expand Up @@ -261,6 +262,7 @@ test_web_in_env:
test_unit:
BUILD_DIR=$(BUILD_DIR) $(MAKE) -C $(CC_ANALYZER) test_unit
BUILD_DIR=$(BUILD_DIR) $(MAKE) -C $(CC_WEB) test_unit
BUILD_DIR=$(BUILD_DIR) $(MAKE) -C $(CC_COMMON)/tests/unit test_unit

test_unit_in_env:
BUILD_DIR=$(BUILD_DIR) $(MAKE) -C $(CC_ANALYZER) test_unit_in_env
Expand Down
20 changes: 17 additions & 3 deletions analyzer/codechecker_analyzer/cmd/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
from codechecker_analyzer import analyzer_context, suppress_handler

from codechecker_common import arg, logger, plist_parser, util, cmd_config
from codechecker_common.output import json as out_json, twodim, codeclimate
from codechecker_common.output import json as out_json, twodim, \
codeclimate, gerrit
from codechecker_common.skiplist_handler import SkipListHandler
from codechecker_common.source_code_comment_handler import \
REVIEW_STATUS_VALUES, SourceCodeCommentHandler, SpellException
Expand All @@ -36,6 +37,8 @@

LOG = logger.get_logger('system')

EXPORT_TYPES = ['html', 'json', 'codeclimate', 'gerrit']


class PlistToPlaintextFormatter(object):
"""
Expand Down Expand Up @@ -375,7 +378,15 @@ def get_argparser_ctor_args():
'epilog': """
environment variables:
CC_SEVERITY_MAP_FILE Path of the checker-severity mapping config file.
CC_REPO_DIR Root directory of the sources, i.e. the directory where
the repository was cloned. Use it when generating gerrit
output.
CC_REPORT_URL URL where the report can be found. Use it when generating
gerrit output.
CC_CHANGED_FILES Path of changed files json from Gerrit. Use it when
generating gerrit output.
Default: {}
""".format(os.path.join(package_root, 'config', 'checker_severity_map.json')),

# Help is shown when the "parent" CodeChecker command lists the
Expand Down Expand Up @@ -426,7 +437,7 @@ def add_arguments_to_parser(parser):
output_opts.add_argument('-e', '--export',
dest="export",
required=False,
choices=['html', 'json', 'codeclimate'],
choices=EXPORT_TYPES,
help="R|Specify extra output format type.\n"
"'codeclimate' format can be used for "
"Code Climate and for GitLab integration. "
Expand Down Expand Up @@ -610,6 +621,9 @@ def parse_convert_reports(input_dirs: List[str],
if out_format == "codeclimate":
return codeclimate.convert(all_reports)

if out_format == "gerrit":
return gerrit.convert(all_reports, severity_map)

if out_format == "json":
return [out_json.convert_to_parse(r) for r in all_reports]

Expand Down Expand Up @@ -688,7 +702,7 @@ def main(args):
'trim_path_prefix' in args else None

if export:
if export not in ['json', 'codeclimate']:
if export not in EXPORT_TYPES:
LOG.error(f"Unknown export format: {export}")
return

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,58 @@ def test_codeclimate_output(self):
}
}])

def test_gerrit_output(self):
""" Test gerrit output of the parse command. """

env = self.env.copy()
report_url = "localhost:8080/index.html"
env["CC_REPORT_URL"] = report_url

changed_file_path = os.path.join(self.test_dir, 'files_changed')

with open(changed_file_path, 'w',
encoding="utf-8", errors="ignore") as changed_file:
# Print some garbage value to the file.
changed_file.write(")]}'\n")

changed_files = {
"/COMMIT_MSG": {},
"macros.cpp": {}}
changed_file.write(json.dumps(changed_files))

env["CC_CHANGED_FILES"] = changed_file_path

test_project_macros = os.path.join(self.test_workspaces['NORMAL'],
"test_files", "macros")
env["CC_REPO_DIR"] = test_project_macros

extract_cmd = ['CodeChecker', 'parse', test_project_macros,
'-e', 'gerrit']

print(" ".join(extract_cmd))
out, _ = call_command(extract_cmd, cwd=self.test_dir, env=env)
print(out)

review_data = json.loads(out)

lbls = review_data["labels"]
self.assertEqual(lbls["Verified"], -1)
self.assertEqual(lbls["Code-Review"], -1)
self.assertEqual(review_data["message"],
"CodeChecker found 1 issue(s) in the code. "
"See: '{0}'".format(report_url))
self.assertEqual(review_data["tag"], "jenkins")

# Because the CC_CHANGED_FILES is set we will see reports only for
# the macro.cpp file.
comments = review_data["comments"]
self.assertEqual(len(comments), 1)

reports = comments["macros.cpp"]
self.assertEqual(len(reports), 1)

os.remove(changed_file_path)

def test_invalid_plist_file(self):
""" Test parsing invalid plist file. """
invalid_plist_file = os.path.join(self.test_workspaces['NORMAL'],
Expand Down
22 changes: 12 additions & 10 deletions codechecker_common/output/gerrit.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,16 @@ def convert(reports: List[Report], severity_map: Dict[str, str]) -> Dict:
changed_file_path = os.environ.get('CC_CHANGED_FILES')
changed_files = __get_changed_files(changed_file_path)

gerrit_reports = __convert_reports(reports, repo_dir, report_url,
changed_files, changed_file_path,
severity_map)
return gerrit_reports
return __convert_reports(reports, repo_dir, report_url,
changed_files, changed_file_path,
severity_map)


def __convert_reports(reports: List[Report],
repo_dir: str,
report_url: str,
repo_dir: Union[str, None],
report_url: Union[str, None],
changed_files: List[str],
changed_file_path: str,
changed_file_path: Union[str, None],
severity_map: Dict[str, str]) -> Dict:
"""Convert the given reports to gerrit json format.
Expand All @@ -60,18 +59,21 @@ def __convert_reports(reports: List[Report],
check_name = report.check_name
severity = severity_map.get(check_name, "UNSPECIFIED")
file_name = report.file_path
checked_file = file_name \
+ ':' + str(bug_line) + ":" + str(bug_col)
check_msg = report.description
source_line = report.line

# Skip the report if it is not in the changed files.
if changed_file_path and not \
any([file_name.endswith(c) for c in changed_files]):
continue

report_count += 1
# file_name can be without a path in the report.
rel_file_path = os.path.relpath(file_name, repo_dir) \
if repo_dir else file_name
if repo_dir and os.path.dirname(file_name) != "" else file_name

checked_file = rel_file_path \
+ ':' + str(bug_line) + ":" + str(bug_col)

if rel_file_path not in review_comments:
review_comments[rel_file_path] = []
Expand Down
13 changes: 13 additions & 0 deletions codechecker_common/tests/.noserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[nosetests]

# increase verbosity level
verbosity=3

# more detailed error messages on failed asserts
detailed-errors=1

# stop running tests on first error
stop=1

# do not capture stdout
#nocapture=1
20 changes: 20 additions & 0 deletions codechecker_common/tests/unit/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Environment variables to run tests.

CURRENT_DIR = $(shell pwd)
# Root of the repository.
REPO_ROOT = $(CURRENT_DIR)/../../../

# Nose test runner configuration options.
NOSECFG = --config .noserc

test_in_env: test_unit_in_env

test: test_unit

UNIT_TEST_CMD = $(REPO_ROOT) nosetests $(NOSECFG) .

test_unit:
$(UNIT_TEST_CMD)

test_unit_in_env: venv_dev
$(ACTIVATE_DEV_VENV) && $(UNIT_TEST_CMD)
17 changes: 17 additions & 0 deletions codechecker_common/tests/unit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# -------------------------------------------------------------------------
#
# Part of the CodeChecker project, under the Apache License v2.0 with
# LLVM Exceptions. See LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# -------------------------------------------------------------------------
"""
Setup python modules for the unit tests.
"""


import os
import sys

REPO_ROOT = os.path.abspath(os.environ['REPO_ROOT'])
sys.path.append(REPO_ROOT)
Loading

0 comments on commit ac43204

Please sign in to comment.