f8bb91bde9592dafe6b30839616bf36fa031f286
[arvados.git] / git / hooks / coding-standards.sh
1 #!/usr/bin/env ruby
2
3 # This script can be installed as a git update hook.
4
5 # It can also be installed as a gitolite 'hooklet' in the
6 # hooks/common/update.secondary.d/ directory.
7
8 # NOTE: this script runs under the same assumptions as the 'update' hook, so
9 # the starting directory must be maintained and arguments must be passed on.
10
11 $refname = ARGV[0]
12 $oldrev  = ARGV[1]
13 $newrev  = ARGV[2]
14 $user    = ENV['USER']
15
16 # Only enforce policy on the master branch
17 exit 0 if $refname != 'refs/heads/master'
18
19 puts "Enforcing Policies... \n(#{$refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})"
20
21 $regex = /\[ref: (\d+)\]/
22
23 $broken_commit_message = /Please enter a commit message to explain why this merge is necessary/
24 $wrong_way_merge_master = /Merge( remote-tracking)? branch '([^\/]+\/)?master' into/
25 $merge_master = /Merge branch '[^']+'((?! into)| into master)/
26 $refs_or_closes_or_no_issue = /(refs #|closes #|no issue #)/i
27
28 # enforced custom commit message format
29 def check_message_format
30   all_revs    = `git rev-list --first-parent #{$oldrev}..#{$newrev}`.split("\n")
31   merge_revs  = `git rev-list --first-parent --min-parents=2 #{$oldrev}..#{$newrev}`.split("\n")
32   # single_revs = `git rev-list --first-parent --max-parents=1 #{$oldrev}..#{$newrev}`.split("\n")
33   broken = false
34
35   merge_revs.each do |rev|
36     message = `git cat-file commit #{rev} | sed '1,/^$/d'`
37     if $wrong_way_merge_master.match(message)
38       puts "\n[POLICY] This appears to be a merge from master into a feature\n"
39       puts "\nbranch.  Commits to master must merge from the feature\n"
40       puts "\nbranch into master.\n\n"
41       puts "\n******************************************************************\n"
42       puts "\nOffending commit: #{rev}\n\n"
43       puts "\nOffending commit message:\n\n"
44       puts message
45       puts "\n******************************************************************\n"
46       puts "\n\n"
47       broken = true
48     elsif not $merge_master.match(message)
49       puts "\n[POLICY] This does not appear to be a merge of a feature\n"
50       puts "\nbranch into master, or it does not follow the required\n"
51       puts "\nformat \"Merge branch 'feature-branch'\".\n\n"
52       puts "\n******************************************************************\n"
53       puts "\nOffending commit: #{rev}\n\n"
54       puts "\nOffending commit message:\n\n"
55       puts message
56       puts "\n******************************************************************\n"
57       puts "\n\n"
58       broken = true
59     end
60   end
61
62   all_revs.each do |rev|
63     message = `git cat-file commit #{rev} | sed '1,/^$/d'`
64     if $broken_commit_message.match(message)
65       puts "\n[POLICY] Rejected broken commit message for including boilerplate\n"
66       puts "\ninstruction text.\n\n"
67       puts "\n******************************************************************\n"
68       puts "\nOffending commit: #{rev}\n\n"
69       puts "\nOffending commit message:\n\n"
70       puts message
71       puts "\n******************************************************************\n"
72       puts "\n\n"
73       broken = true
74     end
75
76     if not $refs_or_closes_or_no_issue.match(message)
77       puts "\n[POLICY] All commits to master must include an issue (\"refs #\" or\n"
78       puts "\n\"closes #\") or specify \"no issue #\"\n\n"
79       puts "\n******************************************************************\n"
80       puts "\nOffending commit: #{rev}\n\n"
81       puts "\nOffending commit message:\n\n"
82       puts message
83       puts "\n******************************************************************\n"
84       puts "\n\n"
85       broken = true
86     end
87   end
88
89   if broken
90     exit 1
91   end
92 end
93
94 check_message_format