forked from aantron/bisect_ppx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.ml
298 lines (245 loc) · 11 KB
/
main.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
(* This file is part of Bisect_ppx, released under the MIT license. See
LICENSE.md for details, or visit
https://github.com/aantron/bisect_ppx/blob/master/LICENSE.md. *)
(* cmdliner wrappers for each of the reports in the other .ml files, and the
program entry point. *)
(* Helpers. *)
let workspace_dir =
match Util.find_dune_workspace_root () with
| None -> "./_build/default"
| Some workspace -> Filename.concat workspace "_build/default"
let esy_source_dir =
match Sys.getenv "cur__target_dir" with
| exception Not_found -> []
| directory -> [Filename.concat directory "default"]
module Term = Cmdliner.Term
module Arg = Cmdliner.Arg
(* Common arguments. *)
let term_info = Term.info ~sdocs:"COMMON OPTIONS"
let coverage_files from_position =
Arg.(value @@ pos_right (from_position - 1) string [] @@
info [] ~docv:"COVERAGE_FILES" ~doc:
("Optional list of *.coverage files produced during testing. If not " ^
"specified, and $(b,--coverage-path) is also not specified, " ^
"bisect-ppx-report will search for *.coverage files non-recursively " ^
"in ./ and recursively in ./_build/, and, if run under esy, inside " ^
"the esy sandbox. If run inside an explicit Dune workspace, ./_build/ " ^
"is taken relative to the workspace root."))
let coverage_paths =
Arg.(value @@ opt_all string [] @@
info ["coverage-path"] ~docv:"DIRECTORY" ~doc:
("Directory in which to look for .coverage files. This option can be " ^
"specified multiple times. The search is recursive in each directory."))
let to_file =
Arg.(required @@ pos 0 (some string) None @@
info [] ~docv:"OUTPUT_FILE" ~doc:"Output file name.")
let source_paths =
Arg.(value @@ opt_all string (["."; workspace_dir] @ esy_source_dir) @@
info ["source-path"] ~docv:"DIRECTORY" ~doc:
("Directory in which to look for source files. This option can be " ^
"specified multiple times. File paths are concatenated with each " ^
"$(b,--source-path) directory when looking for files. The default " ^
"directories are ./ and ./_build/default/. If running inside an esy " ^
"sandbox, the default/ directory in the sandbox is also included. If " ^
"inside an explicit Dune workspace, ./_build/default/ is taken " ^
"relative to the workspace root."))
let ignore_missing_files =
Arg.(value @@ flag @@
info ["ignore-missing-files"] ~doc:
"Do not fail if a particular .ml or .re file can't be found.")
let service_name =
Arg.(value @@ opt string "" @@
info ["service-name"] ~docv:"STRING" ~doc:
"Include \"service_name\": \"$(i,STRING)\" in the generated report.")
let service_number =
Arg.(value @@ opt string "" @@
info ["service-number"] ~docv:"STRING" ~doc:
"Include \"service_number\": \"$(i,STRING)\" in the generated report.")
let service_job_id =
Arg.(value @@ opt string "" @@
info ["service-job-id"] ~docv:"STRING" ~doc:
"Include \"service_job_id\": \"$(i,STRING)\" in the generated report.")
let service_pull_request =
Arg.(value @@ opt string "" @@
info ["service-pull-request"] ~docv:"STRING" ~doc:
("Include \"service_pull_request\": \"$(i,STRING)\" in the generated " ^
"report."))
let repo_token =
Arg.(value @@ opt string "" @@
info ["repo-token"] ~docv:"STRING" ~doc:
"Include \"repo_token\": \"$(i,STRING)\" in the generated report.")
let git =
Arg.(value @@ flag @@
info ["git"] ~doc:"Include git commit info in the generated report.")
let parallel =
Arg.(value @@ flag @@
info ["parallel"] ~doc:
"Include \"parallel\": true in the generated report.")
let expect =
Arg.(value @@ opt_all string [] @@
info ["expect"] ~docv:"PATH" ~docs:"COMMON OPTIONS" ~doc:
("Check that the files at $(i,PATH) are included in the coverage " ^
"report. This option can be given multiple times. If $(i,PATH) ends " ^
"with a path separator (slash), it is treated as a directory name. " ^
"The reporter scans the directory recursively, and expects all files " ^
"in the directory to appear in the report. If $(i,PATH) does not end " ^
"with a path separator, it is treated as the name of a single file, " ^
"and the reporter expects that file to appear in the report. In both " ^
"cases, files expected are limited to those with extensions .ml, " ^
".re, .mll, and .mly. When matching files, extensions are stripped, " ^
"including nested .cppo extensions."))
let do_not_expect =
Arg.(value @@ opt_all string [] @@
info ["do-not-expect"] ~docv:"PATH" ~docs:"COMMON OPTIONS" ~doc:
("Excludes files from those specified with $(b,--expect). This " ^
"option can be given multiple times. If $(i,PATH) ends with a path " ^
"separator (slash), it is treated as a directory name. All files " ^
"found recursively in the directory are then not required to appear " ^
"in the report. If $(i,PATH) does not end with a path separator, it " ^
"is treated as the name of a single file, and that file is not " ^
"required to appear in the report."))
let verbose =
Arg.(value @@ flag @@
info ["verbose"] ~docs:"COMMON OPTIONS" ~doc:"Print diagnostic messages.")
let set_verbose verbose x =
Util.verbose := verbose;
x
(* Subcommands. *)
let html =
let to_directory =
Arg.(value @@ opt string "./_coverage" @@
info ["o"] ~docv:"DIRECTORY" ~doc:"Output directory.")
in
let title =
Arg.(value @@ opt string "Coverage report" @@
info ["title"] ~docv:"STRING" ~doc:"Report title for use in HTML pages.")
in
let tab_size =
Arg.(value @@ opt int 2 @@
info ["tab-size"] ~docv:"N" ~doc:
"Set TAB width for replacing TAB characters in HTML pages.")
in
let theme =
Arg.(value @@
opt (enum ["light", `Light; "dark", `Dark; "auto", `Auto]) `Auto @@
info ["theme"] ~docv:"THEME" ~doc:
("$(i,light) or $(i,dark). The default value, $(i,auto), causes " ^
"the report's theme to adapt to system or browser preferences."))
in
let tree =
Arg.(value @@ flag @@
info ["tree"] ~doc:
("Generate collapsible directory tree with per-directory summaries."))
in
let call_with_labels
to_directory title tab_size theme coverage_files coverage_paths
source_paths ignore_missing_files expect do_not_expect tree =
Html.output
~to_directory ~title ~tab_size ~theme ~coverage_files ~coverage_paths
~source_paths ~ignore_missing_files ~expect ~do_not_expect ~tree
in
Term.(const set_verbose $ verbose $ const call_with_labels $ to_directory
$ title $ tab_size $ theme $ coverage_files 0 $ coverage_paths
$ source_paths $ ignore_missing_files $ expect $ do_not_expect $ tree),
term_info "html" ~doc:"Generate HTML report locally."
~man:[
`S "USAGE EXAMPLE";
`P "Run";
`Pre " bisect-ppx-report html";
`P
("Then view the generated report at _coverage/index.html with your " ^
"browser. All arguments are optional.")
]
let send_to =
let service =
Arg.(required @@ pos 0
(enum ["Codecov", Some `Codecov; "Coveralls", Some `Coveralls]) None @@
info [] ~docv:"SERVICE" ~doc:"'Coveralls' or 'Codecov'.")
in
let dry_run =
Arg.(value @@ flag @@
info ["dry-run"] ~doc:
("Don't issue the final upload command and don't delete the " ^
"intermediate coverage report file."))
in
let call_with_labels
service service_name service_number service_job_id service_pull_request
repo_token git parallel dry_run coverage_files coverage_paths source_paths
ignore_missing_files expect do_not_expect =
Coveralls.output_and_send
~service ~service_name ~service_number ~service_job_id
~service_pull_request ~repo_token ~git ~parallel ~dry_run ~coverage_files
~coverage_paths ~source_paths ~ignore_missing_files ~expect ~do_not_expect
in
Term.(const set_verbose $ verbose $ const call_with_labels $ service
$ service_name $ service_number $ service_job_id $ service_pull_request
$ repo_token $ git $ parallel $ dry_run $ coverage_files 1 $ coverage_paths
$ source_paths $ ignore_missing_files $ expect $ do_not_expect),
term_info "send-to" ~doc:"Send report to a supported web service."
~man:[`S "USAGE EXAMPLE"; `Pre "bisect-ppx-report send-to Coveralls"]
let text =
let per_file =
Arg.(value @@ flag @@
info ["per-file"] ~doc:"Include coverage per source file.")
in
let call_with_labels
per_file coverage_files coverage_paths expect do_not_expect =
Text.output ~per_file ~coverage_files ~coverage_paths ~expect ~do_not_expect
in
Term.(const set_verbose $ verbose $ const call_with_labels
$ per_file $ coverage_files 0 $ coverage_paths $ expect $ do_not_expect),
term_info "summary" ~doc:"Write coverage summary to STDOUT."
let cobertura =
let call_with_labels
to_file coverage_files coverage_paths source_paths ignore_missing_files
expect do_not_expect =
Cobertura.output
~to_file ~coverage_files ~coverage_paths ~source_paths
~ignore_missing_files ~expect ~do_not_expect
in
Term.(const set_verbose $ verbose $ const call_with_labels $ to_file
$ coverage_files 1 $ coverage_paths $ source_paths $ ignore_missing_files
$ expect $ do_not_expect),
term_info "cobertura" ~doc:"Generate Cobertura XML report"
let coveralls =
let call_with_labels
to_file service_name service_number service_job_id service_pull_request
repo_token git parallel coverage_files coverage_paths source_paths
ignore_missing_files expect do_not_expect =
Coveralls.output
~to_file ~service_name ~service_number ~service_job_id
~service_pull_request ~repo_token ~git ~parallel ~coverage_files
~coverage_paths ~source_paths ~ignore_missing_files ~expect ~do_not_expect
in
Term.(const set_verbose $ verbose $ const call_with_labels $ to_file
$ service_name $ service_number $ service_job_id $ service_pull_request
$ repo_token $ git $ parallel $ coverage_files 1 $ coverage_paths
$ source_paths $ ignore_missing_files $ expect $ do_not_expect),
term_info "coveralls" ~doc:
("Generate Coveralls JSON report (for manual integration with web " ^
"services).")
let merge =
let call_with_labels to_file coverage_files coverage_paths =
Merge.output ~to_file ~coverage_files ~coverage_paths
in
Term.(const set_verbose $ verbose $ const call_with_labels $ to_file
$ coverage_files 1 $ coverage_paths),
term_info "merge" ~doc:"Merge coverage files"
(* Entry point. *)
let () =
Term.(eval_choice
(ret (const (`Help (`Auto, None))),
term_info
"bisect-ppx-report"
~doc:"Generate coverage reports for OCaml and Reason."
~man:[
`S "USAGE EXAMPLE";
`Pre
("bisect-ppx-report html\nbisect-ppx-report send-to Coveralls\n" ^
"bisect-ppx-report summary");
`P
("See bisect-ppx-report $(i,COMMAND) --help for further " ^
"information on each command, including options.")
]))
[html; send_to; text; cobertura; coveralls; merge]
|> Term.exit