-
Notifications
You must be signed in to change notification settings - Fork 43
/
check
executable file
·201 lines (171 loc) · 7.87 KB
/
check
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
194
195
196
197
198
199
200
201
#!/usr/bin/env bash
# vim: set ft=sh
set -euo pipefail
exec 3>&1
exec 1>&2
payload=$(mktemp /tmp/resource.XXXXXX)
cat > "${payload}" <&0
# source
bitbucket_type=$(jq -r '.source.bitbucket_type // "server"' < ${payload})
base_url=$(jq -r '.source.base_url // ""' < ${payload})
username=$(jq -r '.source.username // ""' < ${payload})
password=$(jq -r '.source.password // ""' < ${payload})
access_token=$(jq -r '.source.access_token // ""' < ${payload})
project=$(jq -r '.source.project // ""' < ${payload})
repository=$(jq -r '.source.repository // ""' < ${payload})
limit=$(jq -r '.source.limit // 100' < ${payload})
changes_limit=$(jq -r '.source.changes_limit // 100' < ${payload})
source_branch=$(jq -r '.source.branch // ""' < ${payload})
paths=$(jq -r '.source.paths // ""' < ${payload})
direction=$(jq -r '.source.direction // ""' < ${payload})
oauth_id=$(jq -r '.source.oauth_id // ""' < ${payload})
oauth_secret=$(jq -r '.source.oauth_secret // ""' < ${payload})
exclude_title=$(jq -r '.source.exclude_title // "false"' < ${payload})
skip_ssl_verification=$(jq -r '.source.skip_ssl_verification // "false"' < ${payload})
ssl_cacert=$(jq -r '.source.ssl_cacert // ""' < ${payload})
# version
version_updated_at=$(jq -r '.version.updated_at // 0' < ${payload})
if [[ "$bitbucket_type" == "cloud" ]]; then
base_url="https://api.bitbucket.org"
fi
if [[ -z "${base_url}" ]]; then
echo "error: source.base_url can't be empty"
exit 1
fi
if [[ -z "${project}" ]]; then
echo "error: source.project can't be empty"
exit 1
fi
if [[ -z "${repository}" ]]; then
echo "error: source.repository can't be empty"
exit 1
fi
# Check for SSL verification skipping
if [[ "$skip_ssl_verification" == "true" ]]; then
ssl_flag="--insecure"
else
ssl_flag=""
fi
# Check for SSL CA Cert
if [[ -n "${ssl_cacert}" ]]; then
ssl_flag="--cacert ${ssl_cacert}"
fi
# Bitbucket Cloud and (self-hosted) Server APIs are a bit different
if [[ "$bitbucket_type" == "server" ]]; then
request() {
uri="${base_url}/rest/api/1.0/projects/${project}/repos/${repository}${1}"
if [[ -n "${access_token}" ]]; then
curl -sSL ${ssl_flag} --fail -H "Authorization: Bearer ${access_token}" "$uri"
else
curl -sSL ${ssl_flag} --fail -u "${username}:${password}" "$uri"
fi
}
if [[ -n "${source_branch}" ]]; then
branch_param="&at=refs/heads/${source_branch}"
else
branch_param=""
fi
if [[ -n "${direction}" ]]; then
direction_param="&direction=${direction}"
else
direction_param=""
fi
if [[ -f /tmp/pr-last-updated-at ]]; then
version_updated_at=$(cat /tmp/pr-last-updated-at)
fi
prs=$(request "/pull-requests?limit=${limit}&state=open${branch_param}${direction_param}" \
| jq '
.values
| map({
id: .id | tostring,
title: .title | tostring,
branch: .fromRef.id | tostring | (capture("refs/heads/(?<branch>.+)").branch // .),
commit: .fromRef.latestCommit,
updated_at: .updatedDate | tostring
})
')
if [[ -n "${paths}" ]]; then
ids=""
paths=$(jq -r 'join("|^")' <<< $paths)
for id in $(jq -r '.[].id' <<< "$prs"); do
changes=$(request "/pull-requests/${id}/changes?limit=${changes_limit}" \
| jq --arg paths ^$paths '.values | map(.path.toString) | map(select(test($paths))) | any')
[[ $changes != false ]] && ids+="${id},"
done
if [[ -n ${ids} ]]; then
prs=$(jq --argjson ids [${ids::-1}] 'map(select( .id as $in | $ids | index($in | tonumber)))' <<< "$prs")
else
prs="[]"
fi
fi
echo "${prs}" | jq -r 'first | .updated_at' > /tmp/pr-last-updated-at
echo "${prs}" | jq --argjson version_updated_at "${version_updated_at}" --argjson exclude_title "${exclude_title}" '
map(. + {updated_at: .updated_at|tonumber})
| map(select(.updated_at >= $version_updated_at))
| map(select(.title | ascii_downcase | contains("wip") == false))
| if $exclude_title then map(del(.title)) else . end
| sort_by(.updated_at)
| .
| map(del(.updated_at))' >&3
elif [[ "$bitbucket_type" == "cloud" ]]; then
authentication=(-u ${username}:${password})
if [[ -n "${oauth_id}" ]]; then
oauth_response=$(mktemp /tmp/resource.XXXXXX)
uri="https://bitbucket.org/site/oauth2/access_token"
curl -XPOST -sSL ${ssl_flag} --fail -u "${oauth_id}:${oauth_secret}" -d grant_type=client_credentials $uri | jq -r '.access_token' > "${oauth_response}"
authentication=(-H "Authorization: Bearer `cat $oauth_response`")
fi
uri="${base_url}/2.0/repositories/${project}/${repository}/pullrequests?limit=${limit}&state=OPEN"
# write response to file as feeding it to jq from a variable doesnt work properly: JSON looses linefeed format in variable
response=$(mktemp /tmp/resource.XXXXXX)
curl -sSL ${ssl_flag} --fail "${authentication[@]}" $uri | jq -r ".values[0:$limit]" > "${response}"
if [[ "${direction}" == "incoming" ]]; then
branch_object="destination"
else
branch_object="source"
fi
prs="[]"
while read -r pullrequest; do
if [[ "${source_branch}" ]]; then
[[ "$(echo "$pullrequest" | jq -r ".${branch_object}.branch.name")" == "${source_branch}" ]] || continue
fi
id=$(echo "$pullrequest" | jq -r '.id')
title=$(echo "$pullrequest" | jq -r '.title')
branch=$(echo "$pullrequest" | jq -r ".source.branch.name")
commit=$(echo "$pullrequest" | jq -r '.source.commit.hash')
commit_url=$(echo "$pullrequest" | jq -r '.source.commit.links.self.href')
# get the commit date, which is when the PR last got updated code-wise.
# the updated_on field in the PR also changes when comment added etc
date=$(curl -sL --fail "${ssl_flag}" "${authentication[@]}" $commit_url | jq -r '.date')
pr=$(jq -n --arg id "${id}" --arg title "${title}" --arg branch "${branch}" --arg commit "${commit}" --arg date "${date}" '[{id: $id, title: $title, branch: $branch, commit: $commit, updated_at: $date}]')
prs=$(jq -n --argjson prs "${prs}" --argjson pr "${pr}" '$prs + $pr')
done < <(jq -c '.[]' "${response}")
if [[ -n "${paths}" ]]; then
ids=""
paths=$(jq -r 'join("|^")' <<< $paths)
diffstat_response=$(mktemp /tmp/diffstat_response.XXXXXX)
for id in $(jq -r '.[].id' <<< "$prs"); do
uri="${base_url}/2.0/repositories/${project}/${repository}/pullrequests/${id}/diffstat"
curl -sSL ${ssl_flag} --fail "${authentication[@]}" "${uri}" >"${diffstat_response}"
new_changes=$(jq --arg paths ^$paths '[.values[] | select(.new.path != null)] | map(.new.path) | map(select(test($paths))) | any' "${diffstat_response}")
old_changes=$(jq --arg paths ^$paths '[.values[] | select(.old.path != null)] | map(.old.path) | map(select(test($paths))) | any' "${diffstat_response}")
[[ $new_changes != false || $old_changes != false ]] && ids+="${id},"
done
if [[ -n ${ids} ]]; then
prs=$(jq --argjson ids [${ids::-1}] 'map(select( .id as $in | $ids | index($in | tonumber)))' <<< "$prs")
else
prs="[]"
fi
fi
if [[ $(echo "${prs}" | jq length) -eq 0 ]]; then
jq -n "$prs" >&3
exit
fi
# take the list of PRs | filter out containing "wip" in title | sort by update-date of commits | remove the date | pick latest PR, wrap as array for concourse
jq -n --argjson prs "${prs}" --argjson exclude_title "${exclude_title}" '[ $prs
| map(select(if .title | test("wip"; "i") then false else true end))
| if $exclude_title then map(del(.title)) else . end
| sort_by(.updated_at)
| map(del(.updated_at))
| .[-1] ]' >&3
fi