From b9fa783acf0bb9a3702a3d047a8b5e1bf35d99f5 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Fri, 9 Jan 2026 17:06:12 +0300 Subject: [PATCH 1/2] Mapping of path prefixes --- diff-coverage-report.py | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/diff-coverage-report.py b/diff-coverage-report.py index db54f6d..e5b21e4 100755 --- a/diff-coverage-report.py +++ b/diff-coverage-report.py @@ -1,8 +1,8 @@ #!/usr/bin/env python import argparse -from io import IOBase -from re import S +import itertools +import io import jinja2 import os import os.path @@ -14,15 +14,16 @@ def main(argv): args = parse_args(argv) source_dir = os.path.abspath(args.source_dir) + prefix_map = list(itertools.batched(args.map_prefix or [], 2)) with open(args.target_info, 'r') as f: - files = parse_tracefile(f, source_dir) + files = parse_tracefile(f, source_dir, prefix_map) with open(args.base_info, 'r') as f: - files = parse_tracefile(f, source_dir, files) + files = parse_tracefile(f, source_dir, prefix_map, files) with open(args.diff, 'r') as f: - files = parse_diff(f, files, source_dir) + files = parse_diff(f, files, source_dir, prefix_map) dirs = collect_directories(files, source_dir) @@ -91,10 +92,14 @@ def parse_args(argv): parser.add_argument( '-O', '--output-dir', default=os.getcwd(), help=f'Output directory', ) + parser.add_argument( + '-P', '--map-prefix', nargs='*', help=f'Output directory', + ) + return parser.parse_args(argv[1:]) -def parse_tracefile(lines, source_dir, files=None): +def parse_tracefile(lines, source_dir, prefix_map, files=None): is_base = files is not None if not is_base: files = {} @@ -112,7 +117,7 @@ def parse_tracefile(lines, source_dir, files=None): if directive == 'SF': assert cur_file is None - cur_file = FileData(parts[1], source_dir) + cur_file = FileData(fix_path(parts[1], prefix_map), source_dir) elif directive == 'FNL': assert cur_file is not None @@ -203,7 +208,7 @@ def parse_tracefile(lines, source_dir, files=None): return files -def parse_diff(lines, result, source_dir): +def parse_diff(lines, result, source_dir, prefix_map): old_file = None new_file = None file_data = None @@ -228,11 +233,11 @@ def commit(): new_line = -1 _, old_file = l.split(' ', 1) - old_file = fix_path(old_file.rstrip()) + old_file = fix_path(old_file.rstrip(), prefix_map) elif l.startswith('+++ '): _, new_file = l.split(' ', 1) - new_file = fix_path(new_file.rstrip()) + new_file = fix_path(new_file.rstrip(), prefix_map) assert old_file == new_file file_data = result.get(new_file) @@ -314,11 +319,12 @@ def collect_directories(files, source_dir): return dirs.values() -def fix_path(path: str) -> str: - if os.path.isabs(path): - return path - else: - return os.sep.join(path.split(os.sep, 1)[1:]) +def fix_path(path: str, prefix_map) -> str: + for src, tgt in prefix_map: + if path.startswith(src): + path = tgt + path[len(src):] + break + return path def path_suffix(path: str, source_dir: str) -> str: @@ -408,7 +414,7 @@ def __init__(self, path: str, source_dir: str): def output_path(self): return self.source_path + '.html' - def calc(self, text: IOBase): + def calc(self, text: io.IOBase): assert self.base result = [] diff = DiffedLines(text, self) @@ -598,7 +604,7 @@ def add_line(self, number, count, _=None): class DiffedLines(): - def __init__(self, lines: IOBase, data: FileData): + def __init__(self, lines: io.IOBase, data: FileData): self.lines = lines self.data = data From 786936ea008b0a1a831efa16f3b8158c95af8c7e Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Thu, 8 Jan 2026 18:13:47 +0300 Subject: [PATCH 2/2] CI --- .github/actions/build/action.yml | 48 +++++++++++++ .github/workflows/ci.yml | 119 +++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 .github/actions/build/action.yml create mode 100644 .github/workflows/ci.yml diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml new file mode 100644 index 0000000..daac20e --- /dev/null +++ b/.github/actions/build/action.yml @@ -0,0 +1,48 @@ +name: Run and build with coverage +description: Build the project + +inputs: + path: + description: Path to project root + required: true + default: '' + repository: + description: Repository that is being built + required: true + default: '' + ref: + description: Git ref of the state of the project being built + required: true + default: '' + commit: + description: Git commit of the state of the project being built + required: true + default: '' + targets: + description: B2 targets to build (separated by spaces) + required: false + default: '' + +runs: + using: composite + steps: + - name: Setup environment variables + shell: bash + run: | + set -ex + export LCOV_BRANCH_COVERAGE=0 + export B2_TOOLSET=gcc-14 + export CXX=g++-14 + export B2_CI_VERSION=1 + export B2_CXXSTD=20 + export B2_VARIANT=debug + export B2_TARGETS=${{ github.targets }} + export B2_FLAGS="link=shared cxxflags=-fkeep-static-functions cxxflags=--coverage linkflags=--coverage" + export DRONE_BUILD_EVENT=${{ github.event_name }} + export DRONE_JOB_BUILDTYPE=boost + export DRONE_COMMIT=${{ github.sha }} + export DRONE_BRANCH=${{ inputs.ref }} + export DRONE_REPO=${{ inputs.repo }} + + cd ${{ inputs.path }} + . .drone/drone.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..516345d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,119 @@ +name: CI + +on: + push + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Fetch head + uses: actions/checkout@v5 + + - id: fetch-target + name: Fetch Boost.JSON target + uses: actions/checkout@v5 + with: + repository: 'boostorg/json' + ref: 4c97cd0ff39c453043cf1b474bdbcacb1979d0f0 + path: target/root + + - name: Build target + uses: ./.github/actions/build + with: + path: target/root + repository: booostorg/json + ref: ${{ steps.fetch-target.outputs.ref }} + commit: ${{ steps.fetch-target.outputs.commit }} + targets: libs/json/test + + - id: fetch-baseline + name: Fetch Boost.JSON baseline + uses: actions/checkout@v5 + with: + repository: 'boostorg/json' + ref: develop + path: base/root + + - name: Build baseline + uses: ./.github/actions/build + with: + path: base/root + repository: booostorg/json + ref: ${{ steps.fetch-baseline.outputs.ref }} + commit: ${{ steps.fetch-baseline.outputs.commit }} + targets: libs/json/test + + - name: Collect coverage + run: | + set -ex + + sudo apt install lcov + + lcov --rc branch_coverage=0 --rc geninfo_unexecuted_blocks=1 \ + --gcov-tool=gcov-14 --capture --initial --directory base/boost-root/bin.v2/libs/json \ + --output-file base/zero.info + lcov --rc branch_coverage=0 --rc geninfo_unexecuted_blocks=1 \ + --gcov-tool=gcov-14 --capture --directory base/boost-root/bin.v2/libs/json \ + --output-file base/run.info + lcov -a base/zero.info -a base/run.info --output-file base/all.info + lcov --extract base/all.info '*/json/*' --output-file base/filter1.info + lcov --remove base/filter1.info '*/json/test/*' '*/json/bench/*' \ + '*/json/example/*' --output-file base/filter2.info + + lcov --rc branch_coverage=0 --rc geninfo_unexecuted_blocks=1 \ + --gcov-tool=gcov-14 --capture --initial --directory target/boost-root/bin.v2/libs/json \ + --output-file target/zero.info + lcov --rc branch_coverage=0 --rc geninfo_unexecuted_blocks=1 \ + --gcov-tool=gcov-14 --capture --directory target/boost-root/bin.v2/libs/json \ + --output-file target/run.info + lcov -a target/zero.info -a target/run.info --output-file target/all.info + lcov --extract target/all.info '*/json/*' --output-file target/filter1.info + lcov --remove target/filter1.info '*/json/test/*' '*/json/bench/*' \ + '*/json/example/*' --output-file target/filter2.info + + git diff -U0 --no-indent-heuristic --minimal \ + base/boost-root/libs/json target/boost-root/libs/json >diff + + ./diff-coverage-report.py -O pages -S target/boost-root/libs/json \ + -B base/filter2.info -T target/filter2.info -D diff \ + -P $PWD/base/boost-root/boost $PWD/target/boost-root/libs/json/include/boost \ + $PWD/target/boost-root/boost $PWD/target/boost-root/libs/json/include/boost \ + $PWD/base/boost-root $PWD/target/boost-root \ + 1/base/boost-root $PWD/target/boost-root \ + 2/target/boost-root $PWD/target/boost-root + + - name: Save coverage info + uses: actions/upload-artifact@v4 + with: + name: coverage + path: | + base/filter2.info + target/filter2.info + diff + if-no-files-found: error + retention-days: 1 + compression-level: 9 + + - name: Upload result as an artifact + uses: actions/upload-pages-artifact@v3 + with: + path: pages/ + + deploy: + needs: build + + permissions: + pages: write + id-token: write + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4