Skip to content
Open
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
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion web/api/js/codechecker-api-node/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codechecker-api",
"version": "6.69.0",
"version": "6.70.0",
"description": "Generated node.js compatible API stubs for CodeChecker server.",
"main": "lib",
"homepage": "https://github.com/Ericsson/codechecker",
Expand Down
Binary file modified web/api/py/codechecker_api/dist/codechecker_api.tar.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion web/api/py/codechecker_api/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
with open('README.md', encoding='utf-8', errors="ignore") as f:
long_description = f.read()

api_version = '6.69.0'
api_version = '6.70.0'

setup(
name='codechecker_api',
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion web/api/py/codechecker_api_shared/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
with open('README.md', encoding='utf-8', errors="ignore") as f:
long_description = f.read()

api_version = '6.69.0'
api_version = '6.70.0'

setup(
name='codechecker_api_shared',
Expand Down
15 changes: 15 additions & 0 deletions web/api/report_server.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,21 @@ service codeCheckerDBAccess {
5: i64 offset)
throws (1: codechecker_api_shared.RequestFailed requestError),

// Returns detailed report statistics grouped by file.
// The inner map contains total report count ("reports") and
// counts per severity, review status and detection status.
// If the run id list is empty the metrics will be counted
// for all of the runs and in compare mode all of the runs
// will be used as a baseline excluding the runs in compare data.
// PERMISSION: PRODUCT_VIEW
map<string, map<string, i64>> getFileCountsSummary(
1: list<i64> runIds,
2: ReportFilter reportFilter,
3: CompareData cmpData,
4: i64 limit,
5: i64 offset)
throws (1: codechecker_api_shared.RequestFailed requestError),

// If the run id list is empty the metrics will be counted
// for all of the runs and in compare mode all of the runs
// will be used as a baseline excluding the runs in compare data.
Expand Down
5 changes: 5 additions & 0 deletions web/client/codechecker_client/helpers/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ def getDetectionStatusCounts(self, runIds, reportFilter, cmpData):
def getFileCounts(self, runIds, reportFilter, cmpData, limit, offset):
pass

@thrift_client_call
def getFileCountsSummary(self, runIds, reportFilter, cmpData, limit,
offset):
pass

@thrift_client_call
def getCheckerCounts(self, base_run_ids, reportFilter, cmpData, limit,
offset):
Expand Down
2 changes: 1 addition & 1 deletion web/codechecker_web/shared/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# The newest supported minor version (value) for each supported major version
# (key) in this particular build.
SUPPORTED_VERSIONS = {
6: 69
6: 70
}

# Used by the client to automatically identify the latest major and minor
Expand Down
94 changes: 94 additions & 0 deletions web/server/codechecker_server/api/report_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3718,6 +3718,100 @@ def getFileCounts(self, run_ids, report_filter, cmp_data, limit, offset):
results[fp] = count
return results

@exc_to_thrift_reqfail
@timeit
def getFileCountsSummary(self, run_ids, report_filter, cmp_data,
limit, offset):
# Returns detailed report statistics grouped by file.
# The inner map contains total report count ("reports") and
# counts per severity, review status and detection status.
# If the run id list is empty the metrics will be counted
# for all of the runs and in compare mode all of the runs
# will be used as a baseline excluding the runs in compare data.
# PERMISSION: PRODUCT_VIEW
self.__require_view()

limit = verify_limit_range(limit)

results = {}
with DBSession(self._Session) as session:
filter_expression, join_tables = process_report_filter(
session, run_ids, report_filter, cmp_data)

# Get distinct file paths with pagination.
distinct_file_path = session.query(File.filepath.distinct()) \
.join(Report, Report.file_id == File.id)

if report_filter.annotations is not None:
distinct_file_path = distinct_file_path.outerjoin(
ReportAnnotations,
ReportAnnotations.report_id == Report.id)
distinct_file_path = distinct_file_path.group_by(
Report.id)

distinct_file_path = apply_report_filter(
distinct_file_path, filter_expression, join_tables, [File])

if limit:
distinct_file_path = distinct_file_path.limit(limit) \
.offset(offset)

count_col = Report.bug_id.distinct() if \
report_filter.isUnique else Report.bug_id

# Query: file path, severity, review status,
# detection status, and count.
stmt = session.query(
File.filepath,
Checker.severity,
Report.review_status,
Report.detection_status,
func.count(count_col).label('cnt')) \
.join(Report, Report.file_id == File.id) \
.join(Checker, Report.checker_id == Checker.id) \
.filter(File.filepath.in_(distinct_file_path))

stmt = apply_report_filter(
stmt, filter_expression, join_tables, [File, Checker])

stmt = stmt.group_by(
File.filepath,
Checker.severity,
Report.review_status,
Report.detection_status)

severity_names = ttypes.Severity._VALUES_TO_NAMES

for fp, sev, review_st, detect_st, cnt in stmt:
if fp not in results:
results[fp] = {}

file_summary = results[fp]

# Total report count.
file_summary["reports"] = \
file_summary.get("reports", 0) + cnt

# Severity count.
sev_name = severity_names.get(sev, str(sev))
sev_key = f"severity:{sev_name}"
file_summary[sev_key] = \
file_summary.get(sev_key, 0) + cnt

# Review status count.
if review_st:
rs_key = f"review_status:{review_st}"
file_summary[rs_key] = \
file_summary.get(rs_key, 0) + cnt

# Detection status count.
if detect_st:
ds_key = f"detection_status:{detect_st}"
file_summary[ds_key] = \
file_summary.get(ds_key, 0) + cnt

return results

@exc_to_thrift_reqfail
@timeit
def getRunHistoryTagCounts(self, run_ids, report_filter, cmp_data, limit,
Expand Down
67 changes: 67 additions & 0 deletions web/server/vue-cli/e2e/pages/filePathTree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// -------------------------------------------------------------------------
// 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
// -------------------------------------------------------------------------

// Page object for the file-path filter's tree-based menu content
// (FilePathFilter.vue). Shares the same overall layout as the report page
// (login is performed via browser.page.login() in the spec), but only
// exposes the tree-specific elements/sections.

const commands = {
waitForProgressBarNotPresent() {
this.pause(500, () => {
this.waitForElementNotPresent("@progressBar");
});
return this;
},

openFilePathFilterMenu() {
const filterSection = this.section.filePathFilter;
filterSection.click("@expansionBtn");
filterSection.click("@settings");
this.expect.section("@filePathTreeMenu").to.be.visible.before(5000);
return this;
}
};

module.exports = {
url: function() {
return this.api.launchUrl + "/e2e/reports?review-status=Unreviewed&"
+ "review-status=Confirmed%20bug&detection-status=New&"
+ "detection-status=Reopened&detection-status=Unresolved";
},
commands: [ commands ],
elements: {
page: ".v-data-table",
progressBar: ".v-data-table__progress"
},
sections: {
filePathFilter: {
selector: "#filepath",
elements: {
expansionBtn: ".expansion-btn",
settings: ".settings-btn",
clearBtn: ".clear-btn",
selectedItems: ".selected-item"
}
},
filePathTreeMenu: {
// The settings-menu popup that hosts the file-path tree.
selector: ".settings-menu.menuable__content__active",
elements: {
searchInput: "header input[type='text']",
anywhereSwitch: ".v-input--switch",
tree: ".file-path-tree",
treeNode: ".file-path-tree .v-treeview-node",
treeRootNode: ".file-path-tree > .v-treeview-node",
treeNodeRoot: ".file-path-tree .v-treeview-node__root",
treeItemLabel: ".file-path-tree .tree-item-label",
treeCheckbox: ".file-path-tree .v-treeview-node__checkbox",
applyBtn: ".apply-btn",
clearAllBtn: ".clear-all-btn"
}
}
}
};
76 changes: 76 additions & 0 deletions web/server/vue-cli/e2e/pages/reportsTree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// -------------------------------------------------------------------------
// 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
// -------------------------------------------------------------------------

// Page object for the new view-mode toggle (Report List / File Tree)
// and the file-tree container in web/server/vue-cli/src/views/Reports.vue.

const commands = {
waitForProgressBarNotPresent() {
this.pause(500, () => {
this.waitForElementNotPresent("@progressBar");
});
return this;
},

switchToTreeView() {
this
.click("@treeViewBtn")
.pause(500)
.waitForElementNotPresent("@progressBar");
this.expect.element("@treeViewContainer").to.be.visible.before(5000);
return this;
},

switchToTableView() {
this
.click("@tableViewBtn")
.pause(500)
.waitForElementNotPresent("@progressBar");
this.expect.element("@dataTable").to.be.visible.before(5000);
return this;
}
};

module.exports = {
url: function() {
return this.api.launchUrl + "/e2e/reports?review-status=Unreviewed&"
+ "review-status=Confirmed%20bug&detection-status=New&"
+ "detection-status=Reopened&detection-status=Unresolved";
},
commands: [ commands ],
elements: {
page: ".v-data-table",
progressBar: ".v-data-table__progress",

// View-mode toggle (Vuetify v-btn-toggle with two v-btn entries).
viewModeToggle: ".v-btn-toggle",
tableViewBtn: ".v-btn-toggle .v-btn:nth-child(1)",
treeViewBtn: ".v-btn-toggle .v-btn:nth-child(2)",

dataTable: ".v-data-table",

treeViewContainer: ".tree-view-container",
treeHeader: ".tree-view-container .tree-header",
treeHeaderName: ".tree-view-container .tree-header-name",
treeHeaderCell: ".tree-view-container .tree-header-cell",
treeRow: ".tree-view-container .tree-row",
treeItemLabel:
".tree-view-container .tree-item-label.clickable",
treeStatCell: ".tree-view-container .tree-stat-cell"
},
sections: {
// Re-declare the file-path filter section so this spec can assert that
// clicking a tree item populates it.
filePathFilter: {
selector: "#filepath",
elements: {
expansionBtn: ".expansion-btn",
clearBtn: ".clear-btn",
selectedItems: ".selected-item"
}
}
}
};
Loading
Loading