{"id":18244289,"url":"https://github.com/stackb/bazel-jacocorunner","last_synced_at":"2025-08-07T01:32:58.353Z","repository":{"id":64966157,"uuid":"579501366","full_name":"stackb/bazel-jacocorunner","owner":"stackb","description":"Custom jacocorunner for bazel and java toolchains","archived":false,"fork":false,"pushed_at":"2023-05-17T03:57:41.000Z","size":507,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-08T18:51:49.623Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stackb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-17T22:34:20.000Z","updated_at":"2024-02-22T16:13:07.000Z","dependencies_parsed_at":"2025-02-14T14:47:41.620Z","dependency_job_id":"a347746f-565f-45e7-b5a2-780050d4b180","html_url":"https://github.com/stackb/bazel-jacocorunner","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/stackb/bazel-jacocorunner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackb%2Fbazel-jacocorunner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackb%2Fbazel-jacocorunner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackb%2Fbazel-jacocorunner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackb%2Fbazel-jacocorunner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stackb","download_url":"https://codeload.github.com/stackb/bazel-jacocorunner/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackb%2Fbazel-jacocorunner/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269185585,"owners_count":24374619,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-06T02:00:09.910Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T09:16:01.354Z","updated_at":"2025-08-07T01:32:58.326Z","avatar_url":"https://github.com/stackb.png","language":"Java","readme":"\n[![CI](https://github.com/stackb/bazel-jacocorunner/actions/workflows/ci.yaml/badge.svg)](https://github.com/stackb/bazel-jacocorunner/actions/workflows/ci.yaml)\n\n# bazel-jacocorunner\n\n- [bazel-jacocorunner](#bazel-jacocorunner)\n  - [What is this?](#what-is-this)\n- [Usage](#usage)\n  - [`WORKSPACE`](#workspace)\n  - [`.bazelrc`](#bazelrc)\n  - [`coverage.sh`](#coveragesh)\n- [NOTES](#notes)\n  - [How do I know which `java_toolchain` is being used?](#how-do-i-know-which-java_toolchain-is-being-used)\n  - [JacocoCoverageRunner Changes](#jacococoveragerunner-changes)\n  - [Scala Coverage Caveats](#scala-coverage-caveats)\n\n## What is this?\n\n- Bazel's [`jacocorunner` source\n  code](https://github.com/bazelbuild/bazel/blob/master/src/java_tools/junitrunner/java/com/google/testing/coverage/BUILD),\n  copied here so we can more easily build it outside of bazel itself using\n  different jacoco jar dependencies.\n  (see `//java/com/google/testing/coverage`).\n- A custom http_archive rule that downloads @gergelyfabian's [scala-improved\n  fork of jacoco](https://github.com/gergelyfabian/jacoco), builds it with\n  `mvn`, and exposes the maven artifacts as deps (`jacoco_http_archive`).\n- A set of scala+java examples, shamelessly copied from\n  https://github.com/gergelyfabian/bazel-scala-example, which serves as a\n  test-base so we can check that things are working.\n- A `coverage.sh` script that runs `bazel coverage` and then performs\n  lcov/genhtml post-processing on the combined `_coverage_report.dat`.\n- A github workflow `ci.yaml` that runs the tests on new PRs and the `master`\n  branch.\n- A github workflow `release.yaml` that publishes `jacocorunner-{VERSION}.jar`\n  as a release asset.\n- A set of `java_toolchain` and\n  `toolchain\u003c@bazel_tools//tools/jdk:toolchain_type\u003e` in `//tools/jdk` (using\n  the same naming patterns in `@bazel_tools//tools/jdk`) that consume the\n  release asset jar in the `java_toolchain.jacocorunner` attribute.\n\n# Usage\n\nTo use one of the custom java toolchains, you could do something like the\nfollowing:\n\n## `WORKSPACE`\n\n```bazel\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\n\n# --------------------------------------------------------\n# provides @build_stack_bazel_jacocorunner//tools/jdk:*\n# --------------------------------------------------------\n\n# Branch: master\n# Commit: 6b66562185f2700dcdb33c7a5382bde0c7f7d15f\n# Date: 2022-12-20 22:51:53 +0000 UTC\n# URL: https://github.com/stackb/bazel-jacocorunner/commit/6b66562185f2700dcdb33c7a5382bde0c7f7d15f\n# \n# expand toolchain completely\n# Size: 443788 (444 kB)\nhttp_archive(\n    name = \"build_stack_bazel_jacocorunner\",\n    sha256 = \"8c940052ae59e2bf0d15d36e704222f3a9201cc6599b16e4cac2467c66083378\",\n    strip_prefix = \"bazel-jacocorunner-6b66562185f2700dcdb33c7a5382bde0c7f7d15f\",\n    urls = [\"https://github.com/stackb/bazel-jacocorunner/archive/6b66562185f2700dcdb33c7a5382bde0c7f7d15f.tar.gz\"],\n)\n\n# --------------------------------------------------------\n# provides @bazel_jacocorunner//:jar, needed by \n# toolchains in @build_stack_bazel_jacocorunner//tools/jdk\n# --------------------------------------------------------\n\nload(\"@build_stack_bazel_jacocorunner//:repositories.bzl\", \"bazel_jacocorunner\")\n\nbazel_jacocorunner()\n\n# --------------------------------------------------------\n# register a toolchain\n# --------------------------------------------------------\n\nregister_toolchains(\"@build_stack_bazel_jacocorunner//tools/jdk:toolchain_java11_definition\")\n```\n\n## `.bazelrc`\n\n```conf\nbuild:java11 --java_language_version=11\nbuild:java11 --tool_java_language_version=11\nbuild:java11 --java_runtime_version=remotejdk_11\nbuild:java11 --tool_java_runtime_version=remotejdk_11\nbuild:java11 --java_toolchain=@build_stack_bazel_jacocorunner//tools/jdk:toolchain_java11_definition\nbuild:java11 --host_java_toolchain=@build_stack_bazel_jacocorunner//tools/jdk:toolchain_java11_definition\n\ncoverage:combined --combined_report=lcov\ncoverage:combined --coverage_report_generator=\"@bazel_tools//tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator:Main\"\ncoverage:combined --experimental_fetch_all_coverage_outputs\ncoverage:combined --test_env=VERBOSE_COVERAGE=1\n\nbuild --config=java11\ncoverage --config=combined\n```\n\n## `coverage.sh`\n\nIf you want to use lcov/genhtml without having to install them on the host, add\nthe following to your `WORKSPACE`:\n\n```bazel\nload(\"@build_stack_bazel_jacocorunner//:repositories.bzl\", \"lcov_repositories\")\n\nlcov_repositories()\n```\n\nThis could be used something like the following in a shell script:\n\n```sh\n# prebuild some tools so they are in bazel-bin...\nbazel build @linux_test_project_lcov//:genhtml_bin @build_stack_bazel_jacocorunner//tools/covbean\n\n# run your coverage targets and generate the bazel-out/_coverage/_coverage_report.dat file...\nbazel coverage //...\n\n# make a temp directory for the report files\nreportdir=$(mktemp -d /tmp/bazelcov.XXXXXX)\n\n# run genhtml on the output\nbazel-bin/external/linux_test_project_lcov/genhtml_bin \\\n  -branch-coverage \\\n  -o $reportdir \\\n  bazel-out/_coverage/_coverage_report.dat\n\n# optionally, pack the report into an executable zip with an embedded webserver\nlocal covbean_zip=\"$PWD/covbean.zip\"\ncp bazel-bin/external/build_stack_bazel_jacocorunner/tools/covbean/covbean.zip $covbean_zip\nchmod +wx $covbean_zip\n(cd $reportdir \u0026\u0026 zip $covbean_zip .)\n\n# clean up\nrm -rf $reportdir\n\n```\n\nThen you can view your report as follows:\n\n```sh\nsh ./covbean.zip \u0026\nopen http://localhost:8080\n```\n\n# NOTES\n\n## How do I know which `java_toolchain` is being used?\n\nTry building a java target with `--toolchain_resolution_debug='@bazel_tools//tools/jdk:runtime_toolchain_type'`.\n\n```\nINFO: ToolchainResolution: Target platform @rules_nixpkgs_core//platforms:host: Selected execution platform @rules_nixpkgs_core//platforms:host, type @bazel_tools//tools/jdk:runtime_toolchain_type -\u003e toolchain @remotejdk11_macos_aarch64//:jdk\n```\n\n`bazel query @remotejdk11_macos_aarch64//:jdk --output build` resolves to:\n\n```bazel\njava_runtime(\n    name = \"jdk\",\n    srcs = [\n        \"@remotejdk11_macos_aarch64//:jdk-bin\",\n        \"@remotejdk11_macos_aarch64//:jdk-conf\",\n        \"@remotejdk11_macos_aarch64//:jdk-include\",\n        \"@remotejdk11_macos_aarch64//:jdk-lib\",\n        \"@remotejdk11_macos_aarch64//:jre-default\",\n    ],\n)\n```\n\nWe can also see this in `aquery --output text`, which prints out the raw action prototext:\n\n`bazel aquery --output=text //example/lib:hello-world`:\n\n```conf\naction 'Building example/lib/libhello-world.jar (1 source file)'\n  Mnemonic: Javac\n  Target: //example/lib:hello-world\n  Configuration: darwin_arm64-fastbuild\n  Execution platform: @local_config_platform//:host\n  ActionKey: 944e1415223fe32d4855f27591467048e6e6f7dd768beb5d8e4a7dbfb0c3b253\n  Inputs: [...]\n  Environment: [LC_CTYPE=en_US.UTF-8]\n  ExecutionInfo: {internal-inline-outputs: bazel-out/darwin_arm64-fastbuild/bin/example/lib/libhello-world.jdeps, supports-multiplex-workers: 1, supports-worker-cancellation: 1, supports-workers: 1}\n  Command Line: (exec external/remotejdk11_macos_aarch64/bin/java \\\n    -XX:-CompactStrings \\\n    '--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED' \\\n    '--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED' \\\n    '--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED' \\\n    '--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED' \\\n    '--add-exports=jdk.compiler/com.sun.tools.javac.resources=ALL-UNNAMED' \\\n    '--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED' \\\n    '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED' \\\n    '--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED' \\\n    '--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED' \\\n    '--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED' \\\n    '--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED' \\\n    '--add-opens=java.base/java.nio=ALL-UNNAMED' \\\n    '--add-opens=java.base/java.lang=ALL-UNNAMED' \\\n    '-Dsun.io.useCanonCaches=false' \\\n    -jar \\\n    external/remote_java_tools/java_tools/JavaBuilder_deploy.jar \\\n    --output \\\n    bazel-out/darwin_arm64-fastbuild/bin/example/lib/libhello-world.jar \\\n    --native_header_output \\\n    bazel-out/darwin_arm64-fastbuild/bin/example/lib/libhello-world-native-header.jar \\\n    --output_manifest_proto \\\n    bazel-out/darwin_arm64-fastbuild/bin/example/lib/libhello-world.jar_manifest_proto \\\n    --compress_jar \\\n    --output_deps_proto \\\n    bazel-out/darwin_arm64-fastbuild/bin/example/lib/libhello-world.jdeps \\\n    --bootclasspath \\\n    bazel-out/darwin_arm64-fastbuild/bin/external/bazel_tools/tools/jdk/platformclasspath.jar \\\n    --sources \\\n    example/lib/src/main/java/mypackage/Greeter.java \\\n    --javacopts \\\n    -source \\\n    11 \\\n    -target \\\n    11 \\\n    '-XDskipDuplicateBridges=true' \\\n    '-XDcompilePolicy=simple' \\\n    -g \\\n    -parameters \\\n    -Xep:ReturnValueIgnored:OFF \\\n    -- \\\n    --target_label \\\n    //example/lib:hello-world \\\n    --strict_java_deps \\\n    ERROR \\\n    --experimental_fix_deps_tool \\\n    add_dep \\\n    --reduce_classpath_mode \\\n    JAVABUILDER_REDUCED)\n```\n\n## JacocoCoverageRunner Changes\n\nThe `java/com/google/testing/coverage/JacocoLCOVFormatter.java` in this repo\ndiffers a little bit from the one in the bazel repository.  In the original\nrepo, there is a function `.getExecPathForEntryName(String classPath)` that\ntakes the computed name of the `IClassCoverage` and tries to match it against a\nset of paths that are known from scanning files named in the\n`-paths-for-coverage.txt` file in instrumented jar `META-INF/`.  That function\ndoes an `.endswith()` comparison to match files, and if\n`.getExecPathForEntryName` return `null`, coverage will not be generated for\nthat file.  In our case, the layout of files does not exactly match the package\nnames.  Additional logic has been added: if the basenames match and the\n`execPath` contains the package name, this is considered a match.\n\n## Scala Coverage Caveats\n\nWhen scala coverage is run, it creates instrumented jars like\n`mylib-offline.jar` where the bytecode has been instrumented by jacoco.  This\ncreates a runtime dependency of the code to be tested/analyzed for coverage on\nthe jacoco agent code, which is provided by default in rules_scala by\n`@bazel_tools//tools/jdk:JacocoCoverage`.  It turns out different jacoco\nversions have unique internally shaded classnames, for example\n`org/jacoco/agent/rt/internal_f3994fa/core/JaCoCo.class`.  So, if you try and\nanalyze code that has been instrumented by a different jacoco version used\nunder test, you'll get a ClassNotFoundError and coverage will fail\n(will be looking for something like `.../internal_c0314ef/...`).\n\nAs a result, you need to ensure that the same jacoco version is used across the\n`java_toolchain.jacocorunner`, `scala_toolchain.jacocorunner`, and the\n`JacocoInstrumenter.deps`.  It is not possible to configure the `deps` of the\n`rules_scala/src/java/io/bazel/rulesscala/coverage/instrumenter`, so you'll need\nto patch rules_scala with your custom jacocorunner.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackb%2Fbazel-jacocorunner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstackb%2Fbazel-jacocorunner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackb%2Fbazel-jacocorunner/lists"}