Issue-ID: DOC-603
[doc.git] / tools / warnstats.sh
1 #!/bin/bash
2
3 #set -x # uncomment for bash script debugging
4
5 # ============================================================================
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 #       http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 # ============LICENSE_END=====================================================
18
19 ###
20 ### warnstats
21 ###
22 ### AUTHOR(S):
23 ### Thomas Kulik, Deutsche Telekom AG, 2020
24 ###
25 ### DESCRIPTION:
26 ### warnstat helps to find the onap modules (projects) and rst-files which are
27 ### responsible for the most warnings during the documentation build process.
28 ### it requires a tox build logfile, parses it line by line, prints out some
29 ### statistics and provides links to the local rst file, its html version, the
30 ### related link to readthedocs and as well the doc8 test result for the rst.
31 ###
32
33 ###
34 ### CHANGELOG (LATEST ON TOP)
35 ###
36 ### 1.6.1 (2020-04-21) - fixed a problem with duplicates in rst filenames
37 ### 1.6.0 (2020-04-03) - extended detection of docs pathes in case they are not
38 ###                      below the submodules directory
39 ### 1.5.0 (2020-03-23) - doc8 test now executed for every rst file. result is
40 ###                      provided in the output as "doc8_(nnnnn)" where nnnnn
41 ###                      is the total number of accumulated doc8 errors.
42 ###                    - improved readability of output
43 ### 1.4.0 (2020-03-18) - the link to the local html and rst file is provided in
44 ###                      the output. this may help to ease the debug process.
45 ###                      use mouse-over/context menu functionality of bash to
46 ###                      easily open files with your browser or rst editor.
47 ###                    - improved handling for module names (in case they are
48 ###                      no real onap projects/modules but directories which
49 ###                      contain additional documentation in rst format).
50 ### 1.3.1 (2020-03-10) - fixed minor typo in usage message
51 ### 1.3.0 (2020-03-09) - initially released to the community
52 ###
53
54 script_version="1.6.1 (2020-04-21)"
55 doc8_dir=$(pwd)/doc8_results
56 logfile=$1;
57 doc8_command="doc8 --verbose"; #add options if required
58 web_base_url="https://docs.onap.org/en/latest";
59
60 echo " ";
61 echo " warnstats version ${script_version}";
62
63 declare -A module_array
64 declare -A message_short_array
65 declare -A message_long_array
66 declare -A rstfile_array
67 declare -A rstfilepath_array
68 declare -A htmlfilepath_array
69 declare -A webpath_array
70 declare -A doc8_result_array
71
72 ###
73 ### simple script argument handling
74 ###
75
76 # check if there is an argument at all
77 if [[ "$logfile" == "" ]] ; then
78     echo 'Usage: warnstats [tox-logfile]'
79     exit 1
80 fi
81
82 # check if argument is a file
83 if [ ! -f $logfile ] ; then
84     echo "Error: can't find tox-logfile \"$logfile\""
85     exit 1
86 fi
87
88 # create and clean doc8 directory
89 if [ ! -d "$doc8_dir" ]; then
90   mkdir $doc8_dir;
91 else
92   rm ${doc8_dir}/*.txt 2>/dev/null;
93 fi
94
95 # get local html build directory
96 html_build_dir=$(grep "Generated docs available in" $logfile);
97 html_build_dir=$(echo "$html_build_dir" | grep -oP " /.*/doc/docs/_build/html$");
98 html_build_dir=$(echo "$html_build_dir" | sed -r 's:^ ::');
99 echo " html build directory ..... $html_build_dir"
100 echo " web base url ............. $web_base_url";
101 echo " doc8 command ............. $doc8_command";
102 echo " doc8 results directory ... $doc8_dir";
103 echo " tox logfile .............. $logfile";
104
105 # read in the tox build logfile - use only lines which contain a warning
106 readarray -t logfile_array < <(grep ": WARNING:" $logfile);
107
108 # process filtered logfile line by line
109 for line in "${logfile_array[@]}"
110 do
111
112     # count warning lines
113     (( counter++ ));
114     echo -n -e " lines processed .......... $counter (doc8 check may take a while ...)\r";
115
116     #
117     # extract path to local rst file
118     #
119     path_rst=$line;
120     path_rst_debug=$line;
121     #echo "DBUG      line: $line"
122     # remove problematic text in line that causes regex to fail
123     path_rst=$(echo "$path_rst" | sed -r 's:, other instance in.*::');
124     #echo "DBUG path_rst: $path_rst"
125     # grep the rst file path
126     path_rst=$(echo "$path_rst" | grep -oP "^(/|docs).*\.rst");
127     #echo "DBUG path_rst: $path_rst"
128     if [[ "$path_rst" == "" ]] ; then
129       path_rst="path_to_rst_missing"
130       #echo "DBUG       path_rst: $path_rst"
131       #echo "DBUG path_rst_debug: $path_rst_debug"
132     fi
133     # finally embed the full rst path in a message to use mouse-over/context menu of bash to open file
134     path_rst_link='\e]8;;file:'$path_rst'\arst\e]8;;\a';
135     #echo -e "DBUG path_rst: "$path_rst;
136
137     #
138     # extract path to the html version of the local rst file
139     #
140     path_html=$line;
141     #echo "DBUG      line: $line"
142     # remove problematic text in line that causes regex to fail
143     path_html=$(echo "$path_html" | sed -r 's:, other instance in.*::');
144     #echo "DBUG path_html: $path_html"
145     # grep the rst file path and modify it so we get the local html build path; grep a little bit more to be save
146     path_html=$(echo "$path_html" | grep -oP "(^|/)docs(/.*|)/[\w -]*\.rst");
147     #echo "DBUG path_html: $path_html"
148     path_html=$(echo "$path_html" | sed -r 's:^/docs::');
149     #echo "DBUG path_html: $path_html"
150     path_html=$(echo "$path_html" | sed -r 's:.rst:.html:');
151     #echo "DBUG path_html: $path_html"
152     # create also the path to the web version
153     path_web_link='\e]8;;'${web_base_url}${path_html}'\aweb\e]8;;\a';
154     #echo "DBUG path_web_link: $path_web_link"
155     # finally embed the full html path in a message to use mouse-over/context menu of bash to open file
156     path_html_link='\e]8;;file:'${html_build_dir}${path_html}'\ahtml\e]8;;\a';
157     #echo -e "DBUG path_html_link: "$path_html_link;
158
159     # extract module name from line (remove all text before module name; then cut out module name)
160     module=$(echo "$line" | sed -r 's:(^.*/doc/docs/submodules/|^docs/submodules/|checking consistency... )::' | cut -f1 -d\/);
161     #echo "DBUG   line: $line"
162     #echo "DBUG module: $module"
163
164     # in case the extraction has not lead to a valid module name do some additional investigation
165     if [[ "$module" == "" ]] ; then
166
167       if [[ $line =~ doc/docs/release ]] ; then
168           module="docs_release"
169           #echo "DBUG   line: $line"
170           #echo "DBUG module: $module"
171       elif [[ $line =~ doc/docs/use-cases ]] ; then
172           module="docs_use-cases"
173           #echo "DBUG   line: $line"
174           #echo "DBUG module: $module"
175       elif [[ $line =~ doc/docs/guides/onap-developer ]] ; then
176           module="docs_guides_onap-developer"
177           #echo "DBUG   line: $line"
178           #echo "DBUG module: $module"
179       elif [[ $line =~ doc/docs/guides/onap-operator ]] ; then
180           module="docs_guides_onap-operator"
181           #echo "DBUG   line: $line"
182           #echo "DBUG module: $module"
183       elif [[ $line =~ doc/docs/guides/onap-provider ]] ; then
184           module="docs_guides_onap-provider"
185           #echo "DBUG   line: $line"
186           #echo "DBUG module: $module"
187       elif [[ $line =~ doc/docs/guides/onap-user ]] ; then
188           module="docs_guides_onap-user"
189           #echo "DBUG   line: $line"
190           #echo "DBUG module: $module"
191       elif [[ $line =~ doc/docs/guides/overview ]] ; then
192           module="docs_guides_overview"
193           #echo "DBUG   line: $line"
194           #echo "DBUG module: $module"
195       elif [[ $line =~ doc/docs/templates ]] ; then
196           module="docs_templates"
197           #echo "DBUG   line: $line"
198           #echo "DBUG module: $module"
199       elif [[ $line =~ doc/docs/guides ]] ; then
200           module="docs_guides"
201           #echo "DBUG   line: $line"
202           #echo "DBUG module: $module"
203       else
204           module="docs"
205           #echo "DBUG   line: $line"
206           #echo "DBUG module: $module"
207       fi
208
209     fi
210     #echo "DBUG   line: $line";
211     #echo "DBUG module: $module";
212
213     # get the maximum length of the variable entries to adjust table width later on
214     if [[ ${#module} -gt "$maxlength_module" ]]; then
215       maxlength_module=${#module};
216     fi
217     #echo "DBUG maxlength_module=$maxlength_module";
218
219     # extract rst file name from line and do some formatting to use it later as an array name
220     #echo "DBUG line: $line";
221     rstfile=$(echo "$line" | sed -r 's:, other instance in.*::');
222     rstfile=$(echo -e "${rstfile}" | grep -oP "[\w -]*\.rst");
223     rstfile=$(echo -e ${rstfile} | tr '[:blank:]' '_');
224     #echo "DBUG rst-file: $rstfile";
225
226     # get the maximum length of the variable entries to adjust table width later on
227     if [[ ${#rstfile} -gt "$maxlength_rstfile" ]]; then
228       maxlength_rstfile=${#rstfile};
229     fi
230     #echo "DBUG maxlength_rstfile=$maxlength_rstfile";
231
232     # count the number of warnings for the module/rstfile combination
233     (( rstfile_array[$module | $rstfile]++ ));
234
235     # count the number of warnings for the single module
236     #echo "DBUG $module | $rstfile | $message";
237     (( module_array[$module]++ ));
238
239     # now we have all the information to fill the html/rst/web (file) path arrays
240     htmlfilepath_array[$module | $rstfile]=$path_html_link;
241      rstfilepath_array[$module | $rstfile]=$path_rst_link;
242          webpath_array[$module | $rstfile]=$path_web_link;
243
244     # extract the warning message and do some formatting
245     #message=$(echo "$line" | sed -r 's:^/.+WARNING\:\ ::');
246     message=$(echo "$line" | sed -r 's:^.+WARNING\:\ ::');
247     message=$(echo -e ${message} | tr '[:blank:]' '_');
248     message=$(echo -e ${message} | tr '/' '_');
249     message=$(echo -e ${message} | tr '.' '_');
250
251     # remove all characters from message which may cause problems in the shell
252     message="$(echo -e "${message}" | sed -e 's/[^A-Za-z0-9_-]//g')";
253     #echo "DBUG message=\"$message\""
254
255     # count the number of warnings for the single message (long version)
256     message_long="$(echo -e "${message}")";
257     (( message_long_array[$message_long]++ ))
258
259     # reduce length of message to group them more easily and then ...
260     # count the number of warnings for the single message (short version)
261     message_short="$(echo -e "${message}" | cut -c -16)";
262     (( message_short_array[$message_short]++ ))
263
264     # check rst files with doc8 and store results
265     doc8_result_path="${doc8_dir}/${module}-${rstfile}.txt";
266     #echo "DBUG ---------------------------------------------"
267     #echo "DBUG doc8_result_path=\"$doc8_result_path\""
268     # doc8 check only if result file does not exists yet AND if rst file is valid (exists)
269     if [[ ! -f "$doc8_result_path" && -f "$path_rst" ]] ; then
270         echo "FILE:$path_rst" >$doc8_result_path;
271         $doc8_command "$path_rst" >>$doc8_result_path;
272         total_acc_err=$(grep "Total accumulated errors = " $doc8_result_path);
273         #echo "DBUG total_acc_err=$total_acc_err";
274         total_acc_err=$(echo $total_acc_err | sed 's:Total accumulated errors = ::');
275         #echo "DBUG total_acc_err=$total_acc_err";
276         total_acc_err=$(printf "%05d" $total_acc_err);
277         #echo "DBUG command:doc8 ${path_rst} >>${doc8_result_path}";
278         #echo "DBUG total_acc_err=$total_acc_err";
279     fi
280     doc8_result='\e]8;;file:'${doc8_result_path}'\adoc8_('$total_acc_err')\e]8;;\a';
281     doc8_result_array[$module | $rstfile]=$doc8_result;
282
283 done
284
285 #format counter to have always x digits
286 counter=$(printf "%05d" $counter);
287 echo "                                                                      ";
288 echo " $counter LINES WITH WARNING IN FILE '$logfile'";
289
290 echo " ";
291 echo "################################################################################";
292 echo "~~~ MESSAGES LONG ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
293 echo "################################################################################";
294 echo " ";
295
296 #print array content and append to temporary outfile
297 for i in "${!message_long_array[@]}"
298 do
299   m=$i;
300   n=${message_long_array[$i]};
301   ((nc += n))
302   #format counter to have always x digits
303   n=$(printf "%05d" $n);
304   echo " $n | $m" >>tempoutfile;
305 done
306
307 #format counter to have always x digits
308 nc=$(printf "%05d" $nc);
309 echo " $nc WARNINGS IN TOTAL WITH ${#message_long_array[@]} UNIQUE MESSAGES" >>tempoutfile;
310
311 #print a sorted version of the temporary outfile
312 sort -br tempoutfile
313
314 # clean up
315 rm tempoutfile
316 nc=0
317
318 echo " ";
319 echo "################################################################################";
320 echo "~~~ MESSAGES SHORTENED (FOR SIMPLE GROUPING) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
321 echo "################################################################################";
322 echo " ";
323
324 #print array content and append to temporary outfile
325 for i in "${!message_short_array[@]}"
326 do
327   m=$i;
328   n=${message_short_array[$i]};
329   ((nc += n))
330   #format counter to have always x digits
331   n=$(printf "%05d" $n);
332   echo " $n | $m" >>tempoutfile;
333 done
334
335 #format counter to have always x digits
336 nc=$(printf "%05d" $nc);
337 echo " $nc WARNINGS IN TOTAL WITH ${#message_short_array[@]} UNIQUE MESSAGES" >>tempoutfile;
338
339 #print a sorted version of the temporary outfile
340 sort -br tempoutfile
341
342 # clean up
343 rm tempoutfile
344 nc=0
345
346 echo " ";
347 echo "################################################################################";
348 echo "~~~ MODULES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
349 echo "################################################################################";
350 echo " ";
351
352 #create temporary outfile
353 for i in "${!module_array[@]}"
354 do
355   m=$i;
356   n=${module_array[$i]};
357   ((nc += n))
358   n=$(printf "%05d" $n);
359   echo " $n | $m" >>tempoutfile;
360 done
361
362 #format counter to have always x digits
363 nc=$(printf "%05d" $nc);
364 echo " $nc WARNINGS IN TOTAL IN ${#module_array[@]} MODULES" >>tempoutfile;
365
366 #print a sorted version of the temporary outfile
367 sort -br tempoutfile
368 rm tempoutfile
369 nc=0
370
371 echo " ";
372 echo "################################################################################";
373 echo "~~~ MODULES WITH RSTFILES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
374 echo "################################################################################";
375 echo " ";
376
377 #print array content and append to temporary outfile
378 for i in "${!rstfile_array[@]}"
379 do
380   m=$i;
381   n=${rstfile_array[$i]};
382   p=${htmlfilepath_array[$i]}
383   r=${rstfilepath_array[$i]}
384   w=${webpath_array[$i]}
385   d=${doc8_result_array[$i]};
386   #echo "DBUG -------------------------------"
387   #echo "DBUG i=$i"
388   #echo "DBUG m=$m"
389   #echo "DBUG n=$n"
390   #echo "DBUG p=$p"
391   #echo -e "DBUG p=$p"
392   ((nc += n))
393   #format counter to have always x digits
394   n=$(printf "%05d" $n);
395
396   # extend module name to the max for better readability
397   tmp_mod=$(echo "$m" | sed -r 's: \|.+$::');
398   #echo "DBUG tmp_mod=$tmp_mod"
399   len_tmp_mod=${#tmp_mod}
400   to_add="$(($maxlength_module-$len_tmp_mod))"
401   #echo "DBUG to_add=$to_add"
402   while [ $to_add -gt 0 ]; do
403       tmp_mod="${tmp_mod} ";
404       ((to_add--));
405       #echo "DBUG  to_add=$to_add"
406       #echo "DBUG tmp_mod=\"$tmp_mod\""
407   done
408
409   # extend rst name to the max for better readability
410   tmp_rst=$(echo "$m" | sed -r 's:^.+ \| ::');
411   #echo "DBUG tmp_rst=$tmp_rst"
412   len_tmp_rst=${#tmp_rst}
413   to_add="$(($maxlength_rstfile-$len_tmp_rst))"
414   #echo "DBUG to_add=$to_add"
415   while [ $to_add -gt 0 ]; do
416       tmp_rst="${tmp_rst} ";
417       ((to_add--));
418       #echo "DBUG  to_add=$to_add"
419       #echo "DBUG tmp_rst=\"$tmp_rst\""
420   done
421
422   # recombine module and rst names
423   m="${tmp_mod} | ${tmp_rst}";
424
425   # print out to temp file
426   echo -e " $m | $r  $p  $w  $d | $n" >>tempoutfile;
427 done
428
429 #format counter to have always x digits
430 nc=$(printf "%05d" $nc);
431 #in case the name (e.g) index.rst is used multiple times in the same module warnings are combined
432 echo " $nc WARNINGS IN TOTAL IN APPROX. ${#rstfile_array[@]} RST FILES" >>tempoutfile;
433
434 #print a sorted version of the temporary outfile
435 sort -b tempoutfile
436
437 # clean up
438 rm tempoutfile
439 nc=0
440
441 echo " ";
442 echo "################################################################################";
443 echo "~~~ RSTFILES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
444 echo "################################################################################";
445 echo " ";
446
447 #print array content and append to temporary outfile
448 for i in "${!rstfile_array[@]}"
449 do
450   m=$i;
451   n=${rstfile_array[$i]};
452   p=${htmlfilepath_array[$i]}
453   r=${rstfilepath_array[$i]}
454   w=${webpath_array[$i]}
455   d=${doc8_result_array[$i]};
456   ((nc += n))
457   #format counter to have always x digits
458   n=$(printf "%05d" $n);
459
460   # extend module name to the max for better readability
461   tmp_mod=$(echo "$m" | sed -r 's: \|.+$::');
462   #echo "DBUG tmp_mod=$tmp_mod"
463   len_tmp_mod=${#tmp_mod}
464   to_add="$(($maxlength_module-$len_tmp_mod))"
465   #echo "DBUG to_add=$to_add"
466   while [ $to_add -gt 0 ]; do
467       tmp_mod="${tmp_mod} ";
468       ((to_add--));
469       #echo "DBUG  to_add=$to_add"
470       #echo "DBUG tmp_mod=\"$tmp_mod\""
471   done
472
473   # extend rst name to the max for better readability
474   tmp_rst=$(echo "$m" | sed -r 's:^.+ \| ::');
475   #echo "DBUG tmp_rst=$tmp_rst"
476   len_tmp_rst=${#tmp_rst}
477   to_add="$(($maxlength_rstfile-$len_tmp_rst))"
478   #echo "DBUG to_add=$to_add"
479   while [ $to_add -gt 0 ]; do
480       tmp_rst="${tmp_rst} ";
481       ((to_add--));
482       #echo "DBUG  to_add=$to_add"
483       #echo "DBUG tmp_rst=\"$tmp_rst\""
484   done
485
486   # recombine module and rst names
487   m="${tmp_mod} | ${tmp_rst}";
488
489   # print out to temp file
490   echo -e " $n | $m | $r  $p  $w  $d" >>tempoutfile;
491 done
492
493 #format counter to have always x digits
494 nc=$(printf "%05d" $nc);
495 #in case the name (e.g) index.rst is used multiple times in the same module warnings are combined
496 echo " $nc WARNINGS IN TOTAL IN APPROX. ${#rstfile_array[@]} RST FILES" >>tempoutfile;
497
498 #print a sorted version of the temporary outfile
499 sort -br tempoutfile
500
501 # clean up
502 rm tempoutfile
503 nc=0
504
505 echo " ";
506 exit
507
508 ###
509 ### backup code for future extensions
510 ###
511
512 #
513 # Block_quote_ends_without_a_blank_line_unexpected_unindent
514 # Bullet_list_ends_without_a_blank_line_unexpected_unindent
515 # Citation_[\w-]_is_not_referenced
516 # Citation_unit_test_is_not_referenced
517 # Content_block_expected_for_the_code_directive_none_found
518 # Content_block_expected_for_the_container_directive_none_found
519 # Could_not_lex_literal_block_as_bash__Highlighting_skipped
520 # Could_not_lex_literal_block_as_console__Highlighting_skipped
521 # Could_not_lex_literal_block_as_guess__Highlighting_skipped
522 # Could_not_lex_literal_block_as_json__Highlighting_skipped
523 # Could_not_lex_literal_block_as_yaml__Highlighting_skipped
524 # Definition_list_ends_without_a_blank_line_unexpected_unindent
525 # document_isnt_included_in_any_toctree
526 # download_file_not_readable
527 # Duplicate_explicit_target_name
528 # duplicate_label
529 # Enumerated_list_ends_without_a_blank_line_unexpected_unindent
530 # Error_in_code_directive
531 # Error_in_code-block_directive
532 # Error_in_image_directive
533 # Explicit_markup_ends_without_a_blank_line_unexpected_unindent
534 # Field_list_ends_without_a_blank_line_unexpected_unindent
535 # Footnote_[0-9.*]_is_not_referenced
536 # image_file_not_readable
537 # Include_file
538 # Inconsistent_literal_block_quoting
539 # Inline_emphasis_start-string_without_end-string
540 # Inline_interpreted_text_or_phrase_reference_start-string_without_end-string
541 # Inline_strong_start-string_without_end-string
542 # Inline_substitution_reference_start-string_without_end-string
543 # Literal_block_ends_without_a_blank_line_unexpected_unindent
544 # Literal_block_expected_none_found
545 # Malformed_table
546 # Pygments_lexer_name_asn_is_not_known
547 # Title_level_inconsistent
548 # Title_overline__underline_mismatch
549 # Title_overline_too_short
550 # Title_underline_too_short
551 # toctree_contains_reference_to_nonexisting_document
552 # Too_many_autonumbered_footnote_references_only_0_corresponding_footnotes_available
553 # undecodable_source_characters_replacing_with
554 # undefined_label
555 # Unexpected_indentation
556 # Unknown_directive_type_clode-block
557 # unknown_document
558 # Unknown_target_name