Skip to content
Merged
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
27 changes: 20 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,33 @@ to run that script, then refresh your browser.
- Yellow lines contain expressions, some of which were visited, but others not.
- White lines are those that don't contain visitable expressions. They may have type declarations, keywords, or something else that Bisect_ppx did not, or cannot instrument.

You can submit a coverage report to Coveralls.io using [ocveralls][ocveralls].
See also the [advanced usage][advanced].

### Coveralls.io

(**New**) You can generate a Coveralls json report using the `bisect-ppx-report`
tool with the `-coveralls` flag.
Note that Bisect_ppx reports are more precise than Coveralls, which only
considers whole lines as visited or not.
considers whole lines as visited or not. The built in Coveralls reporter will
consider a full line unvisited if any point on that line is not visited,
check the html report to verify precisly which points are not covered.

See also the [advanced usage][advanced].
Example using the built in Coveralls reporter on Travis CI (which sets [`$TRAVIS_JOB_ID`][travis-vars]):

bisect-ppx-report \
-I _build/ \
-coveralls coverage.json \
-service-name travis-ci \
-service-job-id $TRAVIS_JOB_ID \
bisect*.out
curl -L -F json_file=@./coverage.json https://coveralls.io/api/v1/jobs

[without-opam]: https://github.com/aantron/bisect_ppx/blob/master/doc/advanced.md#WithoutOPAM
[ocamlbuild]: https://github.com/aantron/bisect_ppx/blob/master/doc/advanced.md#Ocamlbuild
[oasis]: https://github.com/aantron/bisect_ppx/blob/master/doc/advanced.md#OASIS
[dune]: https://github.com/aantron/bisect_ppx/blob/master/doc/advanced.md#Dune
[ocveralls]: https://github.com/sagotch/ocveralls
[dune]: https://github.com/aantron/bisect_ppx/blob/master/doc/advanced.md#Dune
[advanced]: https://github.com/aantron/bisect_ppx/blob/master/doc/advanced.md


[travis-vars]: https://docs.travis-ci.com/user/environment-variables/#default-environment-variables

<br>

Expand Down
35 changes: 31 additions & 4 deletions src/report/report.ml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type output_kind =
| Csv_output of string
| Text_output of string
| Dump_output of string
| Coveralls_output of string

let report_outputs = ref []

Expand Down Expand Up @@ -37,18 +38,24 @@ let ignore_missing_files = ref false
let add_file f =
raw_coverage_files := f :: !raw_coverage_files

let service_name = ref ""

let service_job_id = ref ""

let repo_token = ref ""

let options = Arg.align [
("-html",
Arg.String (fun s -> add_output (Html_output s)),
"<dir> Output HTML report to <dir> (HTML only)");

("-I",
Arg.String add_search_path,
"<dir> Look for .ml files in <dir> (HTML only)");
"<dir> Look for .ml files in <dir> (HTML/Coveralls only)");

("-ignore-missing-files",
("-ignore-missing-files",
Arg.Set ignore_missing_files,
" Do not fail if an .ml file can't be found (HTML only)");
" Do not fail if an .ml file can't be found (HTML/Coveralls only)");

("-title",
Arg.Set_string report_title,
Expand Down Expand Up @@ -90,6 +97,22 @@ let options = Arg.align [
("-version",
Arg.Unit (fun () -> print_endline Bisect.Version.value; exit 0),
" Print version and exit");

("-coveralls",
Arg.String (fun s -> add_output (Coveralls_output s)),
"<file> Output coveralls json report to <file>");

("-service-name",
Arg.Set_string service_name,
"<string> Service name for Coveralls json (Coveralls only)");

("-service-job-id",
Arg.Set_string service_job_id,
"<string> Service job id for Coveralls json (Coveralls only)");

("-repo-token",
Arg.Set_string repo_token,
"<string> Repo token for Coveralls json (Coveralls only)");
]

let usage =
Expand Down Expand Up @@ -176,7 +199,11 @@ let main () =
| Text_output file ->
generic_output file (Report_text.make !summary_only)
| Dump_output file ->
generic_output file (Report_dump.make ()) in
generic_output file (Report_dump.make ())
| Coveralls_output file ->
Report_coveralls.output verbose file
!service_name !service_job_id !repo_token
search_in_path data points in
List.iter write_output (List.rev !report_outputs)

let () =
Expand Down
108 changes: 108 additions & 0 deletions src/report/report_coveralls.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
(* This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at http://mozilla.org/MPL/2.0/. *)

let file_json verbose indent in_file resolver visited points =

verbose (Printf.sprintf "Processing file '%s'..." in_file);
match resolver in_file with
| None ->
verbose "... file not found";
None
| Some resolved_in_file ->
let cmp_content =
Hashtbl.find points in_file |> Bisect.Common.read_points' in
verbose (Printf.sprintf "... file has %d points" (List.length cmp_content));
let len = Array.length visited in
let pts = (List.map
(fun p ->
let nb =
if Bisect.Common.(p.identifier) < len then
visited.(Bisect.Common.(p.identifier))
else
0 in
(Bisect.Common.(p.offset), nb))
cmp_content) in
let digest = Digest.to_hex (Digest.file resolved_in_file) in
let in_channel = open_in resolved_in_file in
let line_counts =
try
let rec read number acc pts =
try
let _ = input_line in_channel in
let end_ofs = pos_in in_channel in
let before, after =
Report_utils.split (fun (o, _) -> o < end_ofs) pts in
let visited_lowest =
List.fold_left
(fun v (_, nb) ->
match v with
| None -> Some nb
| Some nb' -> if nb < nb' then Some nb else Some nb')
None
before
in
read (number + 1) (visited_lowest::acc) after
with End_of_file -> List.rev acc
in
read 1 [] pts
with e ->
close_in_noerr in_channel;
raise e;
in
close_in_noerr in_channel;
let scounts = List.map (function
| None -> "null"
| Some nb -> Printf.sprintf "%d" nb) line_counts in
let coverage = String.concat "," scounts in
let indent_strings indent l =
let i = String.make indent ' ' in
List.map (fun s -> i ^ s) l in
Some (
[
"{";
Printf.sprintf " \"name\": \"%s\"," in_file;
Printf.sprintf " \"source_digest\": \"%s\"," digest;
Printf.sprintf " \"coverage\": [%s]" coverage;
"}";
]
|> indent_strings indent
|> String.concat "\n"
)

let output verbose file service_name service_job_id repo_token resolver data points =
Report_utils.mkdirs (Filename.dirname file);
let file_jsons =
Hashtbl.fold
(fun in_file visited acc ->
let maybe_json = file_json verbose 8 in_file resolver visited points in
match maybe_json with
| None -> acc
| Some s -> s :: acc)
data
[]
in
let repo_params =
[ "service_name", (String.trim service_name) ;
"service_job_id", (String.trim service_job_id) ;
"repo_token", (String.trim repo_token) ; ]
|> List.filter (fun (_, v) -> (String.length v) > 0)
|> List.map (fun (n, v) ->
Printf.sprintf " \"%s\": \"%s\"," n v)
|> String.concat "\n"
in
let write ch =
Report_utils.output_strings
[ "{" ;
repo_params ;
" \"source_files\": [" ;
(String.concat ",\n" file_jsons) ;
" ]" ;
"}" ;
]
[]
ch
in
match file with
| "-" -> write stdout
| f -> Bisect.Common.try_out_channel false f write
19 changes: 19 additions & 0 deletions src/report/report_coveralls.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
(* This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at http://mozilla.org/MPL/2.0/. *)



(** This module defines the output to Coveralls JSON. *)


val output :
(string -> unit) -> string -> string -> string -> string -> (string -> string option) ->
(string, int array) Hashtbl.t -> (string, string) Hashtbl.t ->
unit
(** [output verbose file service_name service_job_id repo_token resolver data points]
writes a Coveralls JSON [file] for [data]. [verbose] is used for verbose
output. [service_name], [service_job_id], and [repo_token] are each used for the
respective field in the Coveralls JSON, if not the emptry string. [resolver]
associates actual paths to given filenames. [points] gives the marshalled
locations of the points in the file. *)
11 changes: 11 additions & 0 deletions test/unit/fixtures/report/coveralls_reference.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"service_name": "travis-ci",
"service_job_id": "123",
"source_files": [
{
"name": "source.ml",
"source_digest": "f1cdfb92deaa0354af0016d554b21c8e",
"coverage": [2,2,null,2,null,null,null,null,2,2,7,null,null,9,9,null,null,2,2,9,9,null,null,4,0,2,2,2,0,null,null,2,null,null,0,null,null,0,0,0,0,0,0,0,null,null,0,0,0,0,null,null,2,2,2,0,null,2,null,0]
}
]
}
4 changes: 2 additions & 2 deletions test/unit/fixtures/report/reference.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
-;18;36
source.ml;18;36
-;25;45
source.ml;25;45
51 changes: 30 additions & 21 deletions test/unit/fixtures/report/reference.dump
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,34 @@ file "source.ml"
point at offset 355: 2
point at offset 383: 9
point at offset 395: 9
point at offset 429: 0
point at offset 449: 0
point at offset 459: 0
point at offset 487: 0
point at offset 504: 0
point at offset 510: 0
point at offset 516: 0
point at offset 522: 0
point at offset 528: 0
point at offset 542: 0
point at offset 565: 0
point at offset 576: 0
point at offset 613: 0
point at offset 629: 0
point at offset 643: 0
point at offset 656: 0
point at offset 693: 2
point at offset 707: 2
point at offset 726: 2
point at offset 427: 4
point at offset 440: 0
point at offset 451: 2
point at offset 462: 2
point at offset 481: 2
point at offset 502: 2
point at offset 531: 2
point at offset 538: 0
point at offset 553: 2
point at offset 595: 0
point at offset 615: 0
point at offset 625: 0
point at offset 653: 0
point at offset 670: 0
point at offset 676: 0
point at offset 682: 0
point at offset 688: 0
point at offset 694: 0
point at offset 708: 0
point at offset 731: 0
point at offset 742: 0
point at offset 764: 2
point at offset 782: 0
point at offset 779: 0
point at offset 795: 0
point at offset 809: 0
point at offset 822: 0
point at offset 859: 2
point at offset 873: 2
point at offset 892: 2
point at offset 908: 0
point at offset 930: 2
point at offset 948: 0
Loading