From 0c91b07cab13a3b23eed9ea0a8392f6be1527e5e Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Wed, 1 Apr 2026 13:23:43 +0000 Subject: [PATCH 1/4] Implement store_codechecker rule --- src/codechecker_store.bzl | 90 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/codechecker_store.bzl diff --git a/src/codechecker_store.bzl b/src/codechecker_store.bzl new file mode 100644 index 00000000..2e00145d --- /dev/null +++ b/src/codechecker_store.bzl @@ -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", + ), + "url": attr.string( + default = "http://localhost:8001/Default", + doc = "Url to the CodeChecker server. Defaults to http://localhost:8001/Default", + ), + "tag": attr.string( + default = "", + doc = "Tag to add to the analysis.", + ), + "target": attr.label( + allow_files = True, + doc = "Analysis target to be stored.", + ), + }, + 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, +) From 827b16579564f7c71b9f863b556581963f16d6a1 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Tue, 7 Apr 2026 16:59:28 +0200 Subject: [PATCH 2/4] Add test for storing with the custom rule --- test/unit/parse/BUILD | 1 + test/unit/parse/test_parse.py | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/test/unit/parse/BUILD b/test/unit/parse/BUILD index 0f4a0f9f..46973bec 100644 --- a/test/unit/parse/BUILD +++ b/test/unit/parse/BUILD @@ -34,4 +34,5 @@ codechecker_test( targets = [ "c_target", ], + visibility = ["//test/unit/parse:__subpackages__"], ) diff --git a/test/unit/parse/test_parse.py b/test/unit/parse/test_parse.py index 0e6e137a..697362d7 100644 --- a/test/unit/parse/test_parse.py +++ b/test/unit/parse/test_parse.py @@ -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 @@ -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) From e328cb58f72dfd00254d02a7c2820d0150887fac Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Tue, 7 Apr 2026 17:11:59 +0200 Subject: [PATCH 3/4] Update Readme --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index e037cb6f..71afc601 100644 --- a/README.md +++ b/README.md @@ -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). @@ -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", +) +``` +