hs-test: handle error in config serialization
[vpp.git] / extras / scripts / vpp-review
1 #!/usr/bin/perl
2
3 use Data::Dumper;
4 use Env;
5 use File::Glob ':glob';
6
7 #
8 # Use this script to determine the reviewers for a given commit, like so:
9 #
10 # ayourtch@ayourtch-lnx:~/vpp$ ./extras/scripts/vpp-review HEAD
11 # commit 7ea63c597f82412b68b5a565df10e13669b1decb
12 # Author: Andrew Yourtchenko <ayourtch@gmail.com>
13 # Date:   Wed Jul 14 22:44:05 2021 +0200
14 #
15 #     misc: experimental script to get the list of the reviewers for a commit
16 #
17 #     accepts zero or one argument (the commit hash), and outputs
18 #     the detected components, the component maintainers,
19 #     and the final suggested reviewer list
20 #
21 #     Change-Id: Ief671fe837c6201bb11fd05d02af881822b0bb33
22 #     Type: docs
23 #     Signed-off-by: Andrew Yourtchenko <ayourtch@gmail.com>
24 #
25 # :000000 100755 000000000 635dde59f A  extras/scripts/vpp-review
26 #
27 #
28 # Components of files in the commit:
29 #     misc: extras/scripts/vpp-review
30 #
31 # Component misc maintainers:
32 #    vpp-dev Mailing List <vpp-dev@fd.io>
33 #
34 #
35 # Final reviewer list:
36 #    vpp-dev Mailing List <vpp-dev@fd.io>
37 # ayourtch@ayourtch-lnx:~/vpp$
38 #
39
40 #
41 # Read the maintainers file into a hash, indexed by short component name.
42 #
43 sub read_maintainers() {
44         open(F, "MAINTAINERS") || die("Could not open MAINTAINERS file");
45         my $short_name = "";
46         my $long_name = "";
47         my $in_component = 0;
48         my $maintainers = [];
49         my $paths = [];
50         my $exclude_paths = [];
51         my $feature_yaml = [];
52         my $comments = [];
53         my $out = {};
54         while (<F>) {
55                 chomp();
56                 my $aLine = $_;
57                 # print ("LINE: $aLine\n");
58                 if (/^([A-Z]):\s+(.*)$/) {
59                         my $aLetter = $1;
60                         my $aValue = $2;
61                         # print ("LETTER: $aLetter, VALUE: $aValue\n");
62                         if ($aLetter eq "I") {
63                                 $short_name = $aValue;
64                         }
65                         elsif ($aLetter eq "M") {
66                                 push(@{$maintainers}, $aValue);
67                         }
68                         elsif ($aLetter eq "F") {
69                                 push(@{$paths}, $aValue);
70                         }
71                         elsif ($aLetter eq "E") {
72                                 push(@{$exclude_paths}, $aValue);
73                         }
74                         elsif ($aLetter eq "Y") {
75                                 push(@{$feature_yaml}, $aValue);
76                         }
77                         elsif ($aLetter eq "C") {
78                                 push(@{$comments}, $aValue);
79                         } else {
80                            print ("LETTER: $aLetter, VALUE: $aValue\n");
81                         }
82                         # FIXME: deal with all the other letters here
83                 } elsif (/^(\s*)$/) {
84                         if ($in_component) {
85                                 $in_component = 0;
86                                 if ($short_name ne "") {
87                                         my $comp = {};
88                                         $comp->{'short_name'} = $short_name;
89                                         $comp->{'name'} = $long_name;
90                                         $comp->{'maintainers'} = $maintainers;
91                                         $comp->{'paths'} = $paths;
92                                         $comp->{'comments'} = $comments;
93                                         $comp->{'exclude_paths'} = $exclude_paths;
94                                         $comp->{'feature_yaml'} = $feature_yaml;
95                                         $out->{$short_name} = $comp;
96                                         # print("FEATURE: $short_name => $long_name\n");
97                                         $short_name = "";
98                                         $long_name = "";
99                                         $maintainers = [];
100                                         $paths = [];
101                                         $exclude_paths = [];
102                                         $comments = [];
103                                         $feature_yaml = [];
104                                 }
105                         }
106                         # print ("END\n");
107                 } elsif (/^([^\s].*)$/) {
108                         $in_component = 1;
109                         $long_name = $1;
110                 }
111         }
112
113         if ($in_component) {
114                 $in_component = 0;
115                 if ($short_name ne "") {
116                         my $comp = {};
117                         $comp->{'short_name'} = $short_name;
118                         $comp->{'name'} = $long_name;
119                         $comp->{'maintainers'} = $maintainers;
120                         $comp->{'paths'} = $paths;
121                         $comp->{'comments'} = $comments;
122                         $comp->{'exclude_paths'} = $exclude_paths;
123                         $comp->{'feature_yaml'} = $feature_yaml;
124                         $out->{$short_name} = $comp;
125                 }
126
127         }
128
129         return($out);
130 }
131
132 sub match_my_path {
133         my $p = $_[0];
134         my $apath = $_[1];
135         my $root = $_[2];
136
137         my $p1 = $p;
138         $p1 =~ s#\*#[^/]*#g;
139
140         my $pattern = "$root$p1";
141
142         if ($apath =~ /$pattern/) {
143                 return 1;
144         } else {
145                 return 0;
146         }
147 }
148
149 sub match_path_to_list {
150         my $path_list = $_[0];
151         my $apath = $_[1];
152         my $root = $_[2];
153         foreach $p (@{$path_list}) {
154                 if (match_my_path($p, $apath, $root)) {
155                                 return 1;
156                 }
157         }
158         return 0;
159 }
160
161 sub match_path_to_comp_hash {
162         my $chash = $_[0];
163         my $apath = $_[1];
164         my $root = $_[2];
165         my $is_included = match_path_to_list($chash->{'paths'}, $apath, $root);
166         my $is_excluded = match_path_to_list($chash->{'exclude_paths'}, $apath, $root);
167         return ($is_included && !$is_excluded);
168 }
169
170
171 sub match_path {
172         my $components = $_[0];
173         my $apath = $_[1];
174         my $root = $_[2];
175         my $out = [];
176
177         foreach $aCompName (keys %{$components}) {
178                 my $chash = $components->{$aCompName};
179                 if (match_path_to_comp_hash($chash, $apath, $root)) {
180                         push(@{$out}, $aCompName);
181                 }
182         }
183         my $out1 = $out;
184
185         if (scalar @{$out} > 1) {
186                 # not very efficient way to filter out "misc" but oh well.
187                 $out1 = [];
188                 foreach $aval (@{$out}) {
189                         if ($aval ne "misc") {
190                                 push(@{$out1}, $aval);
191                         }
192                 }
193         }
194
195         return ($out1);
196 }
197
198 my $commit_id = $ARGV[0];
199 my $commit_log = `git log --raw -n 1 $commit_id`;
200 my $files = [];
201 foreach my $aLine (split(/[\r\n]+/, $commit_log)) {
202         if ($aLine =~ /^:[0-7]+\s+[0-7]+\s+[0-9a-f]+\s+[0-9a-f]+\s+\S+\s+(\S+)$/) {
203                 push(@{$files}, $1);
204         }
205 }
206
207 my $comp = read_maintainers();
208 my $matched_comps = {};
209 my $matched_reviewers = {};
210
211 print("$commit_log\n\n");
212
213 print("Components of files in the commit:\n");
214
215 foreach $aFile (@{$files}) {
216         my $matches = match_path($comp, $aFile, '');
217         my $matches_str = join(" ", @{$matches});
218         print ("    $matches_str: $aFile\n");
219
220         foreach my $aComp (@{$matches}) {
221                 $matched_comps->{$aComp} = 1;
222         }
223 }
224
225 foreach my $aKey (keys %{$matched_comps}) {
226         print("\nComponent $aKey maintainers:\n");
227         foreach my $aRV (@{$comp->{$aKey}->{'maintainers'}}) {
228                 print("   $aRV\n");
229                 $matched_reviewers->{$aRV} = 1;
230         }
231 }
232
233 print("\n\nFinal reviewer list:\n");
234
235 foreach my $aRV (keys %{$matched_reviewers}) {
236         print("   $aRV\n");
237 }
238 # print Dumper(\$comp);
239
240