Skip to content
Draft
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
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ bazel test ://your_codechecker_rule_name
bazel test ...
```

### Parsing results

You can find the analysis results in the `bazel-bin/` folder, on which you
can run [`CodeChecker store`](https://github.com/Ericsson/codechecker/blob/master/docs/web/user_guide.md#store)
or [`CodeChecker parse`](https://github.com/Ericsson/codechecker/blob/master/docs/analyzer/user_guide.md#parse).
Expand All @@ -232,6 +234,26 @@ CodeChecker parse bazel-bin/your_codechecker_rule_name/codechecker-files/data
CodeChecker store bazel-bin/your_codechecker_rule_name/codechecker-files/data -n "Run name"
```

Alternatively you can use the rule codechecker_store to store the results of the analysis on a CodeChecker server.
For this you will have to load the rule codechecker_store_test from @rules_codechecker//src:codechecker_store.bzl

```python
load(
"@rules_codechecker//src:codechecker_store.bzl",
"codechecker_store_test",
)
```

Then invoke it by creating a target like this:
```python
codechecker_test(
name = "your_codechecker_store_rule_name",
analysis_name = "optional_name_to_save_under",
target = ":your_target",
url = "https://127.0.0.1:8001/your-endpoint",
)
```

<!-- For now, we consider codechecker() to be an internal rule.

### Build-only CodeChecker analysis: `codechecker()`
Expand Down
90 changes: 90 additions & 0 deletions src/codechecker_store.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright 2023 Ericsson AB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Rulesets for storing the results of codechecker on a codechecker server.
"""

def _get_plist_folder_path(ctx):
"""
Determines the folder where the plist files of the analysis reside.
"""
candidate = ctx.files.target[0]
for file in ctx.files.target:
# Only in monolithic rule
if file.is_directory:
return file.short_path
# Assume all plist files are in the same folder in per_file rule

elif file.basename.endswith(".plist"):
candidate = file
return "$(dirname {file})".format(file = candidate.short_path)

def _codechecker_store_impl(ctx):
folder_path = _get_plist_folder_path(ctx)

name = ctx.attr.analysis_name
if name == "":
name = ctx.attr.name

ctx.actions.write(
output = ctx.outputs.test_script,
is_executable = True,
content = """
# We must override home to avoid writing outside the sandbox
export HOME=$TEST_TMPDIR
CodeChecker store {target_folder} --url {url} --name {name}
""".format(
target_folder = folder_path,
url = ctx.attr.url,
name = name,
),
)

run_files = [ctx.outputs.test_script] + ctx.files.target
return [
DefaultInfo(
files = None,
runfiles = ctx.runfiles(files = run_files),
executable = ctx.outputs.test_script,
),
]

codechecker_store_test = rule(
implementation = _codechecker_store_impl,
attrs = {
"analysis_name": attr.string(
default = "",
doc = "Name to store the run under the CodeChecker server. Defaults to the action name",
),
"tag": attr.string(
default = "",
doc = "Tag to add to the analysis.",
),
"target": attr.label(
allow_files = True,
doc = "Analysis target to be stored.",
),
"url": attr.string(
default = "http://localhost:8001/Default",
doc = "Url to the CodeChecker server. Defaults to http://localhost:8001/Default",
),
},
outputs = {
"test_script": "%{name}/store_script.sh",
},
# Can only depend on a test action (codechecker_test/per_file_test)
# if this itself is a test action too.
test = True,
)
1 change: 1 addition & 0 deletions test/unit/parse/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ codechecker_test(
targets = [
"c_target",
],
visibility = ["//test/unit/parse:__subpackages__"],
)
25 changes: 25 additions & 0 deletions test/unit/parse/test_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
runs correctly on the produced report files
"""
import os
from tempfile import TemporaryDirectory
import unittest
from typing import final
from common.base import TestBase
Expand Down Expand Up @@ -74,6 +75,30 @@ def test_store(self):
"unit_test_bazel",
)

def test_store_rule(self):
"""Test: Storing to CodeChecker server with custom rule"""
port = getattr(self, 'port', 8001)
with TemporaryDirectory(dir=".") as temp_dir:
with open(f"{temp_dir}/BUILD", "w", encoding="utf-8") as build_file:
build_file.write(f"""
load(
"//src:codechecker_store.bzl",
"codechecker_store_test"
)

codechecker_store_test(
name = "store_codechecker",
tags = ["manual"],
target = "//test/unit/parse:codechecker",
url = "http://localhost:{port}/Default",
)
""")
ret, _, stderr = self.run_command(
f"bazel test //test/unit/parse/{os.path.basename(temp_dir)}"
":store_codechecker"
)
self.assertEqual(ret, 0, stderr)


if __name__ == "__main__":
unittest.main(buffer=True)
Loading