Skip to content

Commit

Permalink
Multiple run name by using regex at cmd
Browse files Browse the repository at this point in the history
User can get command line results for multiple runs by using Python
regex expression.
  • Loading branch information
csordasmarton committed Jan 24, 2018
1 parent 15e2689 commit 7572ccf
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 26 deletions.
14 changes: 12 additions & 2 deletions docs/user_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1250,7 +1250,12 @@ usage: CodeChecker cmd results [-h] RUN_NAME [-s] [--filter FILTER]
Show the individual analysis reports' summary.
positional arguments:
RUN_NAME Name of the analysis run to show result summaries of.
RUN_NAME Names of the analysis runs to show result summaries of.
This has the following format:
<run_name_1>:<run_name_2>:<run_name_3> where run names
can be a Python regex expression. So if you have
run_1_a_name, run_2_b_name, run_2_c_name, run_3_d_name
then "run_2*:run_3_d_name" selects the last three runs.
Use 'CodeChecker cmd runs' to get the available runs.
optional arguments:
Expand Down Expand Up @@ -1348,7 +1353,12 @@ optional arguments:
-h, --help show this help message and exit
-n RUN_NAME [RUN_NAME ...], --name RUN_NAME [RUN_NAME ...]
Names of the analysis runs to show result count
breakdown for.
breakdown for. This has the following format:
<run_name_1>:<run_name_2>:<run_name_3> where run names
can be a Python regex expression. So if you have
run_1_a_name, run_2_b_name, run_2_c_name, run_3_d_name
then "run_2*:run_3_d_name" selects the last three runs.
Use 'CodeChecker cmd runs' to get the available runs.
-a, --all Show breakdown for all analysis runs.
-s, --suppressed Filter results to only show suppressed entries.
(default: False)
Expand Down
24 changes: 18 additions & 6 deletions libcodechecker/cmd/cmd_line_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ def check_run_names(client, check_names):
return run_info


def get_runs(client, run_names):
run_filter = ttypes.RunFilter()
run_filter.names = run_names

return client.getRunData(run_filter)


def add_filter_conditions(report_filter, filter_str):
"""
This function fills some attributes of the given report filter based on
Expand Down Expand Up @@ -130,9 +137,12 @@ def handle_list_results(args):

client = setup_client(args.product_url)

run_info = check_run_names(client, [args.name])
run_names = map(lambda x: x.strip(), args.name.split(':'))
run_ids = [run.runId for run in get_runs(client, run_names)]

run = run_info.get(args.name)
if not len(run_ids):
LOG.warning("No runs were found!")
sys.exit(1)

limit = constants.MAX_QUERY_SIZE
offset = 0
Expand All @@ -142,13 +152,13 @@ def handle_list_results(args):
add_filter_conditions(report_filter, args.filter)

all_results = []
results = client.getRunResults([run.runId], limit, offset, None,
results = client.getRunResults(run_ids, limit, offset, None,
report_filter, None)

while results:
all_results.extend(results)
offset += limit
results = client.getRunResults([run.runId], limit, offset, None,
results = client.getRunResults(run_ids, limit, offset, None,
report_filter, None)

if args.output_format == 'json':
Expand Down Expand Up @@ -594,8 +604,10 @@ def checker_count(checker_dict, key):

run_ids = None
if 'all_results' not in args:
items = check_run_names(client, args.names)
run_ids = map(lambda run: run.runId, items.values())
run_ids = [run.runId for run in get_runs(client, args.names)]
if not len(run_ids):
LOG.warning("No runs were found!")
sys.exit(1)

all_checkers_report_filter = ttypes.ReportFilter()
all_checkers_report_filter.isUnique = True
Expand Down
24 changes: 19 additions & 5 deletions libcodechecker/libhandlers/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,16 @@ def __register_results(parser):

parser.add_argument(type=str,
dest="name",
metavar='RUN_NAME',
help="Name of the analysis run to show result "
"summaries of. Use 'CodeChecker cmd runs' to "
"get the available runs.")
metavar='RUN_NAMES',
help="Names of the analysis runs to show result "
"summaries of. This has the following format: "
"<run_name_1>:<run_name_2>:<run_name_3> "
"where run names can be a Python regex "
"expression. So if you have run_1_a_name, "
"run_2_b_name, run_2_c_name, run_3_d_name then"
"\"run_2*:run_3_d_name\" selects the last three"
"runs. Use 'CodeChecker cmd runs' to get the "
"available runs.")

__add_filtering_arguments(parser)

Expand Down Expand Up @@ -255,7 +261,15 @@ def __register_sum(parser):
metavar='RUN_NAME',
default=argparse.SUPPRESS,
help="Names of the analysis runs to show result "
"count breakdown for.")
"count breakdown for. This has the following "
"format: <run_name_1>:<run_name_2>:"
"<run_name_3> where run names can be a "
"Python regex expression. So if you have "
"run_1_a_name, run_2_b_name, run_2_c_name, "
"run_3_d_name then \"run_2*:run_3_d_name\""
"selects the last three runs. Use "
"'CodeChecker cmd runs' to get the available "
"runs.")

name_group.add_argument('-a', '--all',
dest="all_results",
Expand Down
6 changes: 3 additions & 3 deletions libcodechecker/server/api/report_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,9 +531,9 @@ def getRunData(self, run_filter):
if run_filter.exactMatch:
q = q.filter(Run.name.in_(run_filter.names))
else:
OR = [Run.name.ilike('%{0}%'.format(
util.escape_like(name)), escape='*') for
name in run_filter.names]
OR = [Run.name.ilike('{0}'.format(conv(
util.escape_like(name, '\\'))), escape='\\') for
name in run_filter.names]
q = q.filter(or_(*OR))

q = q.outerjoin(stmt, Run.id == stmt.c.run_id) \
Expand Down
16 changes: 6 additions & 10 deletions tests/functional/report_viewer_api/test_run_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,39 +48,35 @@ def test_filter_run_names(self):
"There should be two runs for this test.")

# Filter runs which name starts with `test_files_`.
test_runs = self.__get_runs('test_files_')
test_runs = self.__get_runs('test_files_*')
self.assertEqual(len(test_runs), 1,
"There should be one run for this test.")

# Run name filter is case insensitive.
test_runs = self.__get_runs('Test_Files_')
test_runs = self.__get_runs('Test_Files_*')
self.assertEqual(len(test_runs), 1,
"There should be one run for this test.")

# Filter runs which name contains `files_`.
test_runs = self.__get_runs('files_')
test_runs = self.__get_runs('*files_*')
self.assertEqual(len(test_runs), 1,
"There should be one run for this test.")

# Filter runs which name contains `test_files*`.
test_runs = self.__get_runs('test_files*')
self.assertEqual(len(test_runs), 1,
self.assertEqual(len(test_runs), 2,
"There should be one run for this test.")

test_runs = self.__get_runs('_')
test_runs = self.__get_runs('*_*')
self.assertEqual(len(test_runs), 2,
"There should be two runs for this test.")

test_runs = self.__get_runs('*')
self.assertEqual(len(test_runs), 2,
"There should be two runs for this test.")

test_runs = self.__get_runs('**')
self.assertEqual(len(test_runs), 1,
"There should be one run for this test.")

test_runs = self.__get_runs('%')
self.assertEqual(len(test_runs), 1,
self.assertEqual(len(test_runs), 0,
"There should be one run for this test.")

# Filter non existing run.
Expand Down

0 comments on commit 7572ccf

Please sign in to comment.