Statistics
| Branch: | Tag: | Revision:

root / devel / review @ 777ea2c6

History | View | Annotate | Download (4.5 kB)

1 42c067b7 Michael Hanselmann
#!/bin/bash
2 42c067b7 Michael Hanselmann
3 42c067b7 Michael Hanselmann
# Copyright (C) 2009 Google Inc.
4 42c067b7 Michael Hanselmann
#
5 42c067b7 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
6 42c067b7 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
7 42c067b7 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
8 42c067b7 Michael Hanselmann
# (at your option) any later version.
9 42c067b7 Michael Hanselmann
#
10 42c067b7 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
11 42c067b7 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
12 42c067b7 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 42c067b7 Michael Hanselmann
# General Public License for more details.
14 42c067b7 Michael Hanselmann
#
15 42c067b7 Michael Hanselmann
# You should have received a copy of the GNU General Public License
16 42c067b7 Michael Hanselmann
# along with this program; if not, write to the Free Software
17 42c067b7 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 42c067b7 Michael Hanselmann
# 02110-1301, USA.
19 42c067b7 Michael Hanselmann
20 42c067b7 Michael Hanselmann
# To set user mappings, use this command:
21 926feaf1 Manuel Franceschini
#   git config gnt-review.johndoe 'John Doe <johndoe@example.com>'
22 42c067b7 Michael Hanselmann
23 c69a43c8 Michael Hanselmann
# To disable strict mode (enabled by default):
24 c69a43c8 Michael Hanselmann
#   git config gnt-review.strict false
25 c69a43c8 Michael Hanselmann
26 c69a43c8 Michael Hanselmann
# To enable strict mode:
27 c69a43c8 Michael Hanselmann
#   git config gnt-review.strict true
28 c69a43c8 Michael Hanselmann
29 42c067b7 Michael Hanselmann
set -e
30 42c067b7 Michael Hanselmann
31 42c067b7 Michael Hanselmann
# Get absolute path to myself
32 42c067b7 Michael Hanselmann
me_plain="$0"
33 42c067b7 Michael Hanselmann
me=$(readlink -f "$me_plain")
34 42c067b7 Michael Hanselmann
35 42c067b7 Michael Hanselmann
add_reviewed_by() {
36 42c067b7 Michael Hanselmann
  local msgfile="$1"
37 42c067b7 Michael Hanselmann
38 42c067b7 Michael Hanselmann
  grep -q '^Reviewed-by: ' "$msgfile" && return
39 42c067b7 Michael Hanselmann
40 42c067b7 Michael Hanselmann
  perl -i -e '
41 42c067b7 Michael Hanselmann
  my $sob = 0;
42 42c067b7 Michael Hanselmann
  while (<>) {
43 42c067b7 Michael Hanselmann
    if ($sob == 0 and m/^Signed-off-by:/) {
44 42c067b7 Michael Hanselmann
      $sob = 1;
45 42c067b7 Michael Hanselmann
46 42c067b7 Michael Hanselmann
    } elsif ($sob == 1 and not m/^Signed-off-by:/) {
47 42c067b7 Michael Hanselmann
      print "Reviewed-by: \n";
48 42c067b7 Michael Hanselmann
      $sob = -1;
49 42c067b7 Michael Hanselmann
    }
50 42c067b7 Michael Hanselmann
51 42c067b7 Michael Hanselmann
    print;
52 42c067b7 Michael Hanselmann
  }
53 42c067b7 Michael Hanselmann
54 42c067b7 Michael Hanselmann
  if ($sob == 1) {
55 42c067b7 Michael Hanselmann
    print "Reviewed-by: \n";
56 42c067b7 Michael Hanselmann
  }
57 42c067b7 Michael Hanselmann
  ' "$msgfile"
58 42c067b7 Michael Hanselmann
}
59 42c067b7 Michael Hanselmann
60 42c067b7 Michael Hanselmann
replace_users() {
61 42c067b7 Michael Hanselmann
  local msgfile="$1"
62 42c067b7 Michael Hanselmann
63 c69a43c8 Michael Hanselmann
  if perl -i -e '
64 c69a43c8 Michael Hanselmann
  use strict;
65 c69a43c8 Michael Hanselmann
  use warnings;
66 c69a43c8 Michael Hanselmann
67 c69a43c8 Michael Hanselmann
  my $error = 0;
68 c69a43c8 Michael Hanselmann
  my $strict;
69 c69a43c8 Michael Hanselmann
70 42c067b7 Michael Hanselmann
  sub map_username {
71 42c067b7 Michael Hanselmann
    my ($name) = @_;
72 42c067b7 Michael Hanselmann
73 42c067b7 Michael Hanselmann
    return $name unless $name;
74 42c067b7 Michael Hanselmann
75 42c067b7 Michael Hanselmann
    my @cmd = ("git", "config", "--get", "gnt-review.$name");
76 42c067b7 Michael Hanselmann
77 42c067b7 Michael Hanselmann
    open(my $fh, "-|", @cmd) or die "Command \"@cmd\" failed: $!";
78 42c067b7 Michael Hanselmann
    my $output = do { local $/ = undef; <$fh> };
79 42c067b7 Michael Hanselmann
    close($fh);
80 42c067b7 Michael Hanselmann
81 42c067b7 Michael Hanselmann
    if ($? == 0) {
82 42c067b7 Michael Hanselmann
      chomp $output;
83 42c067b7 Michael Hanselmann
      $output =~ s/\s+/ /;
84 42c067b7 Michael Hanselmann
      return $output;
85 42c067b7 Michael Hanselmann
    }
86 42c067b7 Michael Hanselmann
87 c69a43c8 Michael Hanselmann
    unless (defined $strict) {
88 c69a43c8 Michael Hanselmann
      @cmd = ("git", "config", "--get", "--bool", "gnt-review.strict");
89 c69a43c8 Michael Hanselmann
90 c69a43c8 Michael Hanselmann
      open($fh, "-|", @cmd) or die "Command \"@cmd\" failed: $!";
91 c69a43c8 Michael Hanselmann
      $output = do { local $/ = undef; <$fh> };
92 c69a43c8 Michael Hanselmann
      close($fh);
93 c69a43c8 Michael Hanselmann
94 c69a43c8 Michael Hanselmann
      $strict = ($? != 0 or not $output or $output !~ m/^false$/);
95 c69a43c8 Michael Hanselmann
    }
96 c69a43c8 Michael Hanselmann
97 c69a43c8 Michael Hanselmann
    if ($strict and $name !~ m/^.+<.+\@.+>$/) {
98 c69a43c8 Michael Hanselmann
      $error = 1;
99 c69a43c8 Michael Hanselmann
    }
100 c69a43c8 Michael Hanselmann
101 42c067b7 Michael Hanselmann
    return $name;
102 42c067b7 Michael Hanselmann
  }
103 42c067b7 Michael Hanselmann
104 42c067b7 Michael Hanselmann
  while (<>) {
105 42c067b7 Michael Hanselmann
    if (m/^Reviewed-by:(.*)$/) {
106 42c067b7 Michael Hanselmann
      my @names = grep {
107 42c067b7 Michael Hanselmann
        # Ignore empty entries
108 42c067b7 Michael Hanselmann
        !/^$/
109 42c067b7 Michael Hanselmann
      } map {
110 42c067b7 Michael Hanselmann
        # Normalize whitespace
111 42c067b7 Michael Hanselmann
        $_ =~ s/(^\s+|\s+$)//g;
112 42c067b7 Michael Hanselmann
        $_ =~ s/\s+/ /g;
113 42c067b7 Michael Hanselmann
114 42c067b7 Michael Hanselmann
        # Map names
115 42c067b7 Michael Hanselmann
        $_ = map_username($_);
116 42c067b7 Michael Hanselmann
117 42c067b7 Michael Hanselmann
        $_;
118 42c067b7 Michael Hanselmann
      } split(m/,/, $1);
119 42c067b7 Michael Hanselmann
120 c69a43c8 Michael Hanselmann
      # Get unique names
121 c69a43c8 Michael Hanselmann
      my %saw;
122 c69a43c8 Michael Hanselmann
      @names = grep(!$saw{$_}++, @names);
123 c69a43c8 Michael Hanselmann
      undef %saw;
124 c69a43c8 Michael Hanselmann
125 42c067b7 Michael Hanselmann
      foreach (sort @names) {
126 42c067b7 Michael Hanselmann
        print "Reviewed-by: $_\n";
127 42c067b7 Michael Hanselmann
      }
128 42c067b7 Michael Hanselmann
    } else {
129 42c067b7 Michael Hanselmann
      print;
130 42c067b7 Michael Hanselmann
    }
131 42c067b7 Michael Hanselmann
  }
132 c69a43c8 Michael Hanselmann
133 c69a43c8 Michael Hanselmann
  exit($error? 33 : 0);
134 42c067b7 Michael Hanselmann
  ' "$msgfile"
135 c69a43c8 Michael Hanselmann
  then
136 c69a43c8 Michael Hanselmann
    :
137 c69a43c8 Michael Hanselmann
  else
138 c69a43c8 Michael Hanselmann
    [[ "$?" == 33 ]] && return 1
139 c69a43c8 Michael Hanselmann
    exit 1
140 c69a43c8 Michael Hanselmann
  fi
141 42c067b7 Michael Hanselmann
142 42c067b7 Michael Hanselmann
  if ! grep -q '^Reviewed-by: ' "$msgfile"
143 42c067b7 Michael Hanselmann
  then
144 42c067b7 Michael Hanselmann
    echo 'Missing Reviewed-by: line' >&2
145 42c067b7 Michael Hanselmann
    sleep 1
146 42c067b7 Michael Hanselmann
    return 1
147 42c067b7 Michael Hanselmann
  fi
148 42c067b7 Michael Hanselmann
149 42c067b7 Michael Hanselmann
  return 0
150 42c067b7 Michael Hanselmann
}
151 42c067b7 Michael Hanselmann
152 42c067b7 Michael Hanselmann
run_editor() {
153 42c067b7 Michael Hanselmann
  local filename="$1"
154 42c067b7 Michael Hanselmann
  local editor=${EDITOR:-vi}
155 42c067b7 Michael Hanselmann
  local args
156 42c067b7 Michael Hanselmann
157 42c067b7 Michael Hanselmann
  case "$(basename "$editor")" in
158 42c067b7 Michael Hanselmann
    vi* | *vim)
159 42c067b7 Michael Hanselmann
      # Start edit mode at Reviewed-by: line
160 42c067b7 Michael Hanselmann
      args='+/^Reviewed-by: +nohlsearch +startinsert!'
161 42c067b7 Michael Hanselmann
    ;;
162 42c067b7 Michael Hanselmann
    *)
163 42c067b7 Michael Hanselmann
      args=
164 42c067b7 Michael Hanselmann
    ;;
165 42c067b7 Michael Hanselmann
  esac
166 42c067b7 Michael Hanselmann
167 42c067b7 Michael Hanselmann
  $editor $args "$filename"
168 42c067b7 Michael Hanselmann
}
169 42c067b7 Michael Hanselmann
170 42c067b7 Michael Hanselmann
commit_editor() {
171 42c067b7 Michael Hanselmann
  local msgfile="$1"
172 42c067b7 Michael Hanselmann
173 42c067b7 Michael Hanselmann
  local tmpf=$(mktemp)
174 42c067b7 Michael Hanselmann
  trap "rm -f $tmpf" EXIT
175 42c067b7 Michael Hanselmann
176 42c067b7 Michael Hanselmann
  cp "$msgfile" "$tmpf"
177 42c067b7 Michael Hanselmann
178 42c067b7 Michael Hanselmann
  while :
179 42c067b7 Michael Hanselmann
  do
180 42c067b7 Michael Hanselmann
    add_reviewed_by "$tmpf"
181 42c067b7 Michael Hanselmann
182 42c067b7 Michael Hanselmann
    run_editor "$tmpf"
183 42c067b7 Michael Hanselmann
184 42c067b7 Michael Hanselmann
    replace_users "$tmpf" && break
185 42c067b7 Michael Hanselmann
  done
186 42c067b7 Michael Hanselmann
187 42c067b7 Michael Hanselmann
  cp "$tmpf" "$msgfile"
188 42c067b7 Michael Hanselmann
}
189 42c067b7 Michael Hanselmann
190 42c067b7 Michael Hanselmann
copy_commit() {
191 42c067b7 Michael Hanselmann
  local rev="$1" target_branch="$2"
192 42c067b7 Michael Hanselmann
193 42c067b7 Michael Hanselmann
  echo "Copying commit $rev ..."
194 42c067b7 Michael Hanselmann
195 42c067b7 Michael Hanselmann
  git cherry-pick -n "$rev"
196 42c067b7 Michael Hanselmann
  GIT_EDITOR="$me --commit-editor \"\$@\"" git commit -c "$rev" -s
197 42c067b7 Michael Hanselmann
}
198 42c067b7 Michael Hanselmann
199 53726a00 Guido Trotter
usage() {
200 53726a00 Guido Trotter
  echo "Usage: $me_plain [from..to] <target-branch>" >&2
201 53726a00 Guido Trotter
  echo "  If not passed from..to defaults to target-branch..HEAD" >&2
202 53726a00 Guido Trotter
  exit 1
203 53726a00 Guido Trotter
}
204 42c067b7 Michael Hanselmann
205 53726a00 Guido Trotter
main() {
206 53726a00 Guido Trotter
  local range target_branch
207 53726a00 Guido Trotter
208 53726a00 Guido Trotter
  case "$#" in
209 53726a00 Guido Trotter
  1)
210 53726a00 Guido Trotter
    target_branch="$1"
211 53726a00 Guido Trotter
    range="$target_branch..$(git rev-parse HEAD)"
212 53726a00 Guido Trotter
  ;;
213 53726a00 Guido Trotter
  2)
214 53726a00 Guido Trotter
    range="$1"
215 53726a00 Guido Trotter
    target_branch="$2"
216 53726a00 Guido Trotter
    if [[ "$range" != *..* ]]; then
217 53726a00 Guido Trotter
      usage
218 53726a00 Guido Trotter
    fi
219 53726a00 Guido Trotter
  ;;
220 53726a00 Guido Trotter
  *)
221 53726a00 Guido Trotter
    usage
222 53726a00 Guido Trotter
  ;;
223 53726a00 Guido Trotter
  esac
224 42c067b7 Michael Hanselmann
225 42c067b7 Michael Hanselmann
  git checkout "$target_branch"
226 42c067b7 Michael Hanselmann
  local old_head=$(git rev-parse HEAD)
227 42c067b7 Michael Hanselmann
228 42c067b7 Michael Hanselmann
  for rev in $(git rev-list --reverse "$range")
229 42c067b7 Michael Hanselmann
  do
230 42c067b7 Michael Hanselmann
    copy_commit "$rev"
231 42c067b7 Michael Hanselmann
  done
232 42c067b7 Michael Hanselmann
233 42c067b7 Michael Hanselmann
  git log "$old_head..$target_branch"
234 42c067b7 Michael Hanselmann
}
235 42c067b7 Michael Hanselmann
236 42c067b7 Michael Hanselmann
if [[ "$1" == --commit-editor ]]
237 42c067b7 Michael Hanselmann
then
238 42c067b7 Michael Hanselmann
  shift
239 42c067b7 Michael Hanselmann
  commit_editor "$@"
240 42c067b7 Michael Hanselmann
else
241 42c067b7 Michael Hanselmann
  main "$@"
242 42c067b7 Michael Hanselmann
fi