From b85277923c0c15500fa2c9e6df5185a4d34377f7 Mon Sep 17 00:00:00 2001 From: SuperAuguste <19855629+SuperAuguste@users.noreply.github.com> Date: Fri, 21 Jul 2023 19:45:06 +0200 Subject: [PATCH] coverage: add coverage CI action --- .github/workflows/kcov-json-to-summary.sh | 41 +++++++++++++ .github/workflows/kcov.yml | 70 +++++++++++++++++++++++ build.zig | 37 ++++++++---- 3 files changed, 137 insertions(+), 11 deletions(-) create mode 100755 .github/workflows/kcov-json-to-summary.sh create mode 100644 .github/workflows/kcov.yml diff --git a/.github/workflows/kcov-json-to-summary.sh b/.github/workflows/kcov-json-to-summary.sh new file mode 100755 index 0000000000..76da684109 --- /dev/null +++ b/.github/workflows/kcov-json-to-summary.sh @@ -0,0 +1,41 @@ +# script for us in kcov.yml action + +SUMMARY=$(cat zig-out/kcov/kcov-merged/coverage.json) + +PERCENT_COVERED=$(echo $SUMMARY | jq .percent_covered -cr) +COVERED_LINES=$(echo $SUMMARY | jq .covered_lines -cr) +TOTAL_LINES=$(echo $SUMMARY | jq .total_lines -cr) + +echo -e "## Code Coverage Report\n" +echo -e "### $PERCENT_COVERED% covered ($COVERED_LINES / $TOTAL_LINES lines)\n" + +echo -e "
Per-file coverage details
\n" + +FILES=$(echo $SUMMARY | jq '.files | sort_by(.percent_covered | tonumber) | .[]' -cr) + +echo "| File | Coverage | |" +echo "| ---- | -------- | - |" + +for FILE in $FILES; do + FILENAME="$(echo $FILE | jq '.file' -cr)" + FILENAME=${FILENAME#*zls/} + FILE_PERCENT_COVERED=$(echo $FILE | jq '.percent_covered' -cr) + FILE_COVERED_LINES=$(echo $FILE | jq '.covered_lines' -cr) + FILE_TOTAL_LINES=$(echo $FILE | jq '.total_lines' -cr) + + FILE_STATUS=$( + if [ $(echo $FILE_PERCENT_COVERED'<25' | bc -l) -eq 1 ]; + then + echo "❗" + elif [ $(echo $FILE_PERCENT_COVERED'<75' | bc -l) -eq 1 ]; + then + echo "⚠️" + else + echo "✅" + fi + ) + + echo "| \`$FILENAME\` | $FILE_PERCENT_COVERED% ($FILE_COVERED_LINES / $FILE_TOTAL_LINES lines) | $FILE_STATUS |" +done + +echo "
" diff --git a/.github/workflows/kcov.yml b/.github/workflows/kcov.yml new file mode 100644 index 0000000000..96b96f8891 --- /dev/null +++ b/.github/workflows/kcov.yml @@ -0,0 +1,70 @@ +name: Code Coverage + +on: + pull_request: + types: [opened, synchronize] + +permissions: + pull-requests: write + +jobs: + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + submodules: true + + - uses: goto-bus-stop/setup-zig@v2 + with: + version: master + + - run: zig version + - run: zig env + + - name: Build + run: zig build + + # - name: Build kcov + # run: | + # sudo apt-get update + # sudo apt-get install binutils-dev libssl-dev libcurl4-openssl-dev zlib1g-dev libdw-dev libiberty-dev + # git clone https://github.com/SimonKagstrom/kcov + # cd kcov + # mkdir build + # cd build + # sudo cmake .. + # sudo make + # sudo make install + + - name: Install kcov + run: | + sudo apt-get update + sudo apt-get install kcov + + - name: Run Tests with kcov + id: kcov + env: # Or as an environment variable + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + run: | + mkdir -p zig-out/kcov + + zig build test -Dgenerate_coverage + + tree zig-out/kcov + + .github/workflows/kcov-json-to-summary.sh > zig-out/summary.md + cat zig-out/summary.md > $GITHUB_STEP_SUMMARY + + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + echo "report<<$EOF" >> "$GITHUB_OUTPUT" + cat zig-out/summary.md >> "$GITHUB_OUTPUT" + echo "$EOF" >> "$GITHUB_OUTPUT" + + - name: Publish coverage status + uses: thollander/actions-comment-pull-request@v2 + with: + message: | + ${{ steps.kcov.outputs.report }} + comment_tag: coverage diff --git a/build.zig b/build.zig index b5eaca769a..a9dc7ec9ca 100644 --- a/build.zig +++ b/build.zig @@ -216,31 +216,46 @@ pub fn build(b: *std.build.Builder) !void { if (coverage) { const include_pattern = b.fmt("--include-pattern=/src", .{}); const exclude_pattern = b.fmt("--exclude-pattern=/src/stage2", .{}); - const args = &[_]std.build.RunStep.Arg{ - .{ .bytes = b.dupe("kcov") }, - .{ .bytes = b.dupe("--collect-only") }, - .{ .bytes = b.dupe(include_pattern) }, - .{ .bytes = b.dupe(exclude_pattern) }, - .{ .bytes = b.dupe(coverage_output_dir) }, - }; var tests_run = b.addRunArtifact(tests); var src_tests_run = b.addRunArtifact(src_tests); tests_run.has_side_effects = true; src_tests_run.has_side_effects = true; - tests_run.argv.insertSlice(0, args) catch @panic("OOM"); - src_tests_run.argv.insertSlice(0, args) catch @panic("OOM"); + tests_run.argv.insertSlice(0, &[_]std.build.RunStep.Arg{ + .{ .bytes = b.dupe("kcov") }, + .{ .bytes = b.dupe(include_pattern) }, + .{ .bytes = b.dupe(exclude_pattern) }, + .{ .bytes = b.pathJoin(&.{ coverage_output_dir, "test-tests" }) }, + }) catch @panic("OOM"); + + src_tests_run.argv.insertSlice(0, &[_]std.build.RunStep.Arg{ + .{ .bytes = b.dupe("kcov") }, + .{ .bytes = b.dupe(include_pattern) }, + .{ .bytes = b.dupe(exclude_pattern) }, + .{ .bytes = b.pathJoin(&.{ coverage_output_dir, "test-src" }) }, + }) catch @panic("OOM"); var merge_step = std.build.RunStep.create(b, "merge kcov"); merge_step.has_side_effects = true; + merge_step.addArgs(&.{ "kcov", "--merge", + }); + + if (b.env_map.get("COVERALLS_REPO_TOKEN")) |repo_token| { + std.log.info("Detected repo token; enabling automatic upload to Coveralls", .{}); + merge_step.addArg(std.mem.concat(b.allocator, u8, &[_][]const u8{ "--coveralls-id=", repo_token }) catch @panic("OOM")); + } + + merge_step.addArgs(&.{ coverage_output_dir, - b.pathJoin(&.{ coverage_output_dir, "test" }), + b.pathJoin(&.{ coverage_output_dir, "test-tests" }), + b.pathJoin(&.{ coverage_output_dir, "test-src" }), }); - merge_step.step.dependOn(&b.addRemoveDirTree(coverage_output_dir).step); + + // merge_step.step.dependOn(&b.addRemoveDirTree(coverage_output_dir).step); merge_step.step.dependOn(&tests_run.step); merge_step.step.dependOn(&src_tests_run.step); test_step.dependOn(&merge_step.step);