-
Notifications
You must be signed in to change notification settings - Fork 2
/
git-commit-merge
executable file
·193 lines (155 loc) · 5.79 KB
/
git-commit-merge
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
#!/usr/bin/env bash
set -e -o pipefail
# set -x
## ------------- options handling
VERIFY=true
COMMIT=true
GETOPT="/usr/local/opt/gnu-getopt/bin/getopt"
if [[ ! -x "$GETOPT" ]]; then
GETOPT=$(type -P getopt)
fi
OPTS=$($GETOPT -o '' -l no-verify,no-commit -n git-commit-merge -- "$@")
eval set -- "$OPTS"
while true; do
case "$1" in
--no-verify ) VERIFY=false; shift ;;
--no-commit ) COMMIT=false; shift ;;
-- ) shift; break ;;
* ) break ;;
esac
done
# --------------------
test -n "$(command -v rg)" || exit 1
test -n "$(command -v lsdiff)" || exit 1
test -n "$(command -v grepdiff)" || exit 1
tmpfile=$(mktemp)
function cleanup {
rm -rf "$tmpfile"
}
trap cleanup EXIT
function em() {
if [[ -t 2 ]]; then
printf '\033[1;36m%s\033[0m\n' "$1"
else
# shellcheck disable=SC2016
printf '`%s`' "$1"
fi
}
function error() {
if [[ -t 2 ]]; then
echo -n -e '\033[1;31mERROR\033[0m 🙅 ' >&2
else
echo -n 'ERROR ' >&2
fi
echo "$@" >&2
exit 1
}
# check version of grepdiff
# needs https://github.com/twaugh/patchutils/pull/25 and https://github.com/twaugh/patchutils/pull/26
cat << EOF | grepdiff --only-match=add '\ba' > "$tmpfile"
--- f
+++ f
@@ -0 +1 @@
+a
EOF
# shellcheck disable=SC2016
cat << EOF | cmp - "$tmpfile" 2>/dev/null || error 'wrong `grepdiff` value (should be compiled with PCRE2)'
f
EOF
if ! git diff-index --quiet HEAD -- odoo/release.py; then
error "release.py changed"
fi
un=$(git status --porcelain -uall | grep -cvE '^[DMARC] ' || true)
if test "${un}" -ne 0; then
error "unstaged/untracked files"
fi
# builtin trailing spaces and conflits markers check
# NOTE: for po(t) files, you may want to deactivate whitespace checks via a (global) `.gitattribute` file
:<<'GITATTRIBUTE'
*.po whitespace=-blank-at-eol,-blank-at-eof
*.pot whitespace=-blank-at-eol,-blank-at-eof
GITATTRIBUTE
if ! git diff-index --check --cached HEAD -- >&2; then
error "git diff --check failed"
fi
branch=$(git symbolic-ref --short HEAD)
diff=$(git diff -z --cached --diff-filter=ACM HEAD)
python="python3"
if [[ "$branch" != "master" && ${branch//[-.sa]/} -lt 110 ]]; then
python="python2"
fi
lsdiff -i '*.py' <<< "$diff" | xargs -r -- "$python" -m compileall -q
function assert_not_in_diff() {
ext_filtering=$(awk 'BEGIN{RS=",";ORS=" ";}{ print "-i *." $1 }' <<< "$1")
pattern=$2
unpat=$(awk '{ print gensub(/\\([.[(|)\]$])|\\b/, "\\1", "g") }' <<< "$pattern")
message=${3:-"usage of $(em "$unpat") found."}
# deactivate shell globbing. The `-i` arguments are directly used by `grepdiff` (via fnmatch).
set -o noglob
# shellcheck disable=SC2086
found=$(grepdiff $ext_filtering --only-match=add "$pattern" <<< "$diff")
set +o noglob
test -z "$found" || error -e "[$branch] $message\n$found"
}
# -------- checks
function check_120() {
# can have false positives, use `--no-verify` in this case
assert_not_in_diff py '\.compute\(' "the method $(em compute) of $(em res.currency) is deprecated"
assert_not_in_diff js,xml "\bhidden\b" "Use $(em d-none) class instead of $(em hidden)"
}
function check_saas123() {
COMPAT_OK="(csv_reader|csv_writer|to_text|reraise)"
assert_not_in_diff py \
"(\bpycompat\.(?!$COMPAT_OK\())|(\bfrom odoo\.tools\.pycompat import (?!$COMPAT_OK(, ?)?)+)"\
"$(em pycompat) usage found"
assert_not_in_diff py "\btrack_(visibility|sequence)\b" "$(em "track_visibility/sequence") usage found"
assert_not_in_diff xml "\b@class\b" "Use $(em hasclass\(\)) in xpath expression"
assert_not_in_diff js '\$\.when\('
assert_not_in_diff js '\$\.Deferred\('
assert_not_in_diff js '\.(done|always)\('
assert_not_in_diff js '\bweb_editor\.base\b'
assert_not_in_diff js 'QUnit\..+,(?! async) function' "QUnit $(em "non async function") found"
}
function check_saas124() {
assert_not_in_diff '*' '\baccount\.invoice\b'
assert_not_in_diff py '\benv.(?:do_)?in_onchange\b'
assert_not_in_diff py '\benv\.user\.company_id\b' "Use $(em env.company) instead of $(em env.user.company_id)"
assert_not_in_diff py '\b_company_default_get\b'
assert_not_in_diff py '\bdatas_fname\b'
assert_not_in_diff py '\bself\.phantom_js\(' "Use $(em self.start_tour) helper instead of $(em self.phantom_js)"
}
function check_saas125() {
assert_not_in_diff py '@api\.multi\b'
assert_not_in_diff py '\.sudo\((?!True\)|False\)|\))' "Use $(em with_user) to change active user"
assert_not_in_diff py '\boldname\b'
assert_not_in_diff py '\bcontext_dependent\b'
assert_not_in_diff py '\brelated_sudo\b'
# even if there is little to no chance that these patterns are used...
assert_not_in_diff py '\benv.(?:do_)?in_draft\b'
assert_not_in_diff py '\b\._recompute_todo\b'
assert_not_in_diff py '\benv\.norecompute\b'
# see odoo/odoo@58a2ffa26f1a3b0f9630ce16d11b758d18e20a21
assert_not_in_diff py,xml '\bimage_(original|big|large|medium|small)\b' \
"Use $(em image_DDD) instead [original => 1920; big => 1024; large => 256; medium => 128; small => 128]"
}
function check_master() {
assert_not_in_diff py '\b(?:import|from) openerp\b'
assert_not_in_diff py '\bassert_\b'
assert_not_in_diff py '\bassert(?:Not|Almost)?Equals\b'
assert_not_in_diff py '\bassertRaisesRegexp\b'
assert_not_in_diff py '\bassertRegexpMatches\b'
}
# --------- main
if [[ $VERIFY = true ]]; then
assert_not_in_diff js "\bdebugger\b" "$(em debugger) keyword found"
assert_not_in_diff py "\b(set_trace|pu\.db|breakpoint|import q)\b" "debugging keyword found"
func="check_${branch//[-.]/}"
if declare -f "$func" >/dev/null; then
$func
fi
fi
if [[ $COMMIT = true ]]; then
git commit --no-edit --no-verify --cleanup=strip
else
echo "Automatic verification went well; stopped before committing as requested"
fi