kdc: Finish incomplete warning message
[heimdal.git] / tools / coveralls-tool
blob981bd1757bef30952187cd79d860ff65b735cd5d
1 #!/bin/bash
3 # This script collates gcov data after one has configured with --enable-gcov,
4 # built, and run tests. It either outputs or POSTs to Coveralls a JSON text in
5 # the schema for the Coveralls API, which is documented here:
7 # https://docs.coveralls.io/api-introduction
8 # https://docs.coveralls.io/api-reference
10 # Currently only files in source languages supported by gcov(1) are reported
11 # on, though this can easily be extended. Currently that's only C/C++ files.
13 # This script is specifically written for Heimdal, which is an open source C
14 # codebases that uses autoconf and libtool for its build system. This means
15 # that sometimes the gcov notes and data files are not necessarily where the
16 # gcov(1) utility would find them, which is why this script exists instead of
17 # using some other integration script.
19 # Although this is specific to Heimdal, it can be extended.
21 # Note that one side effect of running this script, gcov(1) will be run for all
22 # C/C++ source files in the workspace. As well, some gcov notes and data files
23 # maybe hard-linked to other names. However, this script should be idempotent.
25 set -euo pipefail
26 set +o noglob
28 PROG=${0##*/}
30 job=${TRAVIS_JOB_ID:-}
31 out=
32 post=false
33 repo=
34 flst=
35 quiet=false
36 branch=
37 srcdir=$PWD
38 objdir=
39 token=${COVERALLS_REPO_TOKEN:-}
40 origin=
41 verbose=0
43 function usage {
44 ((${1:-1})) && exec 1>&2
45 cat <<EOF
46 Usage: $PROG [OPTIONS]
47 Options:
49 -q Quiet. Do not even emit warnings.
50 -v Verbose (on stderr). May be given multiple times.
51 -o - Output to stdout instead of POSTing to Coveralls.
52 -o FILE Output to FILE instead of POSTing to Coveralls.
53 -s CI-NAME Name of CI (e.g., "travis-ci")
54 Defaults to travis-ci.
55 -t TOKEN Token for Coveralls.
56 Defaults to \$COVERALLS_REPO_TOKEN.
57 -b BRANCH Name of branch the report is for.
58 Defaults to \$TRAVIS_BRANCH or currently-checked out branch in
59 SRCDIR.
60 -J ID Job ID (e.g., Travis-CI job ID)
61 Defaults to \${TRAVIS_JOB_ID}.
62 -i FILE Lists source files to run gcov(1) against
63 Defaults to \<(git ls-files -- '*.c' '*.cpp').
64 -S SRCDIR Path to workspace
65 Defaults to \${PWD}.
66 -O OBJDIR Path to object directory if workspace is built out of tree
67 Defaults to SRCDIR.
68 -U ORIGIN Name of origin.
69 Defaults to tracked upstream remote of BRANCH.
70 -R URI Repository URI
71 Defaults to git@github.com:\${TRAVIS_REPO_SLUG} or the push URI
72 for the ORIGIN remote of the workspace at SRCDIR.
74 $PROG will look for .gcno and .gcda files in OBJDIR for source files
75 in the workspace at SRCDIR and will run gcov on them, and produce
76 a request body as JSON in FILE (or stdout if -o FILE not given)
77 for the Coveralls API.
79 If -o FILE is not given, then $PROG will POST the JSON to Coveralls.
80 If -o FILE is given, then $PROG will not POST it to Coveralls.
82 If SRCDIR == OBJDIR == \$PWD, then -S and -O need not be given.
83 If running in a Travis-CI build, -J, -R, and -b need not be given, and -t
84 should not be given -- instead you should set a secret COVERALLS_REPO_TOKEN
85 environment variable in your project's Travis-CI's settings.
87 Only C and C++ source files are reported on. E.g., Yacc/Bison/Flex
88 source files are not reported.
90 The resulting JSON output is or can be POSTed to Coveralls with:
92 $ curl -sfg -X POST -F "json_file=@\${FILE}" -F "Filename=json_file" \\
93 https://coveralls.io/api/v1/jobs
94 EOF
95 exit ${1:-1}
98 while getopts +:J:O:R:S:U:b:hi:o:qs:t:vx opt; do
99 case "$opt" in
100 J) job=$OPTARG;;
101 O) cd "$OPTARG"; objdir=$PWD; cd "$OLDPWD";;
102 R) repo=$OPTARG;;
103 S) cd "$OPTARG"; srcdir=$PWD; cd "$OLDPWD";;
104 U) origin=$OPTARG;;
105 b) branch=;;
106 h) usage 0;;
107 i) flst=$OPTARG;;
108 o) out=$OPTARG;;
109 q) quiet=true; verbose=0;;
110 s) ci=$OPTARG;;
111 t) token=$OPTARG;;
112 v) quiet=false; ((verbose++)) || true; ((verbose > 3)) && set -vx;;
113 *) usage 1;;
114 esac
115 done
117 # Note: we don't cd to $srcdir or $objdir or anywhere, so if $out is a relative
118 # path, we do the right thing.
120 : ${objdir:=${srcdir}}
121 : ${branch:=${TRAVIS_BRANCH:-$(cd "$srcdir" && git rev-parse --abbrev-ref HEAD)}}
123 if [[ -z ${origin:-} ]]; then
124 origin=$(
125 git for-each-ref \
126 --format="%(refname:short) %(upstream:remotename)" refs/heads |
127 while read gb gr; do
128 [[ $gb = $branch ]] || continue
129 printf '%s\n' "$gr"
130 break
131 done
135 if [[ -z ${repo:-} ]]; then
136 if [[ -n ${TRAVIS_REPO_SLUG:-} ]]; then
137 repo=git@github.com:${TRAVIS_REPO_SLUG:-heimdal/heimdal}
138 else
139 repo=$(cd "$srcdir" && git remote get-url --push "$origin")
143 if ((verbose > 1)); then
144 exec 3>&2
145 else
146 exec 3>/dev/null
150 function cleanup {
151 [[ -n $d ]] && rm -rf "$d"
154 trap cleanup EXIT
155 d=$(mktemp -d)
156 touch "${d}/f"
158 declare -a gcov
160 (cd "$srcdir" &&
161 if [[ -n $flst ]]; then cat "$flst"; else git ls-files -- '*.c' '*.cpp'; fi) |
162 while read f; do
163 # Remember to be careful to refer to ${srcdir}/${f}
164 ((verbose)) && printf 'Processing: %s\n' "$f" 1>&2
166 dir=${f%/*}
167 base=${f##*/}
168 base=${base%.*}
170 if [[ ! -f ${objdir}/${dir}/.libs/${base}.gcda && ! -f ${objdir}/${dir}/${base}.gcda ]]; then
171 # Look for .libs/libfoo_la-${base}.gcda -- we don't know "foo", and
172 # there may be more than one!
173 gcda=
174 for gcda in ${objdir}/${dir}/.libs/*_la-${base}.gcda; do
175 break
176 done
177 gcno=
178 for gcno in ${objdir}/${dir}/.libs/*_la-${base}.gcno; do
179 break
180 done
181 [[ -n $gcno && -f $gcno ]] && ln -f "$gcno" "${objdir}/${dir}/.libs/${base}.gcno"
182 [[ -n $gcda && -f $gcda ]] && ln -f "$gcda" "${objdir}/${dir}/.libs/${base}.gcda"
183 if [[ ( -n $gcda && ! -f $gcda ) || ( -n $gcno && ! -f $gcno ) ]]; then
184 $quiet || printf 'Warning: %s has no gcov notes file\n' "$f" 1>&2
185 continue
189 if [[ -f ${objdir}/${dir}/.libs/${base}.gcda ]]; then
190 ((verbose > 1)) && printf 'Running gcov for %s using gcda from .libs\n' "$f" 1>&2
191 if ! (cd "${objdir}/${f%/*}"; ((verbose > 2)) && set -vx; gcov -o .libs "${f##*/}") 1>&3; then
192 $quiet || printf 'Warning: gcov failed for %s\n' "$f" 1>&2
193 continue
195 elif [[ -f ${objdir}/${dir}/${base}.gcda ]]; then
196 if ! (cd "${objdir}/${f%/*}"; ((verbose > 2)) && set -vx; gcov "${f##*/}") 1>&3; then
197 $quiet || printf 'Warning: gcov failed for %s\n' "$f" 1>&2
198 continue
202 if [[ ! -f ${objdir}/${f}.gcov ]]; then
203 $quiet || printf 'Warning: gcov did not produce a .gcov file for %s\n' "$f" 1>&2
204 continue
207 md5=$(md5sum "${srcdir}/${f}")
208 md5=${md5%% *}
210 jq -Rn --arg sum "${md5}" --arg f "$f" '
212 name: $f,
213 source_digest: $sum,
214 coverage: [
215 inputs
216 | split(":")
217 | (.[1] |= tonumber)
218 | select(.[1] > 0)
219 | if .[0]|endswith("#")
220 then 0
221 elif .[0]|endswith("-")
222 then null
223 else .[0]|tonumber
227 ' "${objdir}/${f}.gcov" >> "${d}/f"
228 done
230 function make_report {
231 jq -s --arg job "$job" \
232 --arg ci "${ci:-travis-ci}" \
233 --arg token "$token" \
234 --arg repo "$repo" \
235 --arg branch "$branch" \
236 --arg upstream "$origin" \
237 --arg head "$(git log -n1 --format=%H)" \
238 --arg subject "$(git log -n1 --format=%s)" \
239 --arg aN "$(git log -n1 --format=%aN)" \
240 --arg ae "$(git log -n1 --format=%ae)" \
241 --arg cN "$(git log -n1 --format=%cN)" \
242 --arg ce "$(git log -n1 --format=%ce)" \
244 service_job_id: $job,
245 service_name: $ci,
246 repo_token: $token,
247 git: {
248 id: $head,
249 author_name: $aN,
250 author_email: $ae,
251 committer_name: $cN,
252 committer_email: $ce,
253 message: $subject,
254 branch: $branch,
255 remotes: [ {
256 "name": $upstream,
257 "url": $repo
261 source_files: .
262 }' "${d}/f"
265 if [[ -z $out ]]; then
266 post=true
267 make_report > "${d}/out"
268 elif [[ $out = - ]]; then
269 make_report
270 else
271 make_report > "${out}"
274 if $post && [[ $out != /dev/stdout ]]; then
275 curl -sfg -X POST -F "json_file=@${d}/out" -F "Filename=json_file" \
276 https://coveralls.io/api/v1/jobs