Send coverage data from Travis to Coveralls
authorNicolas Williams <nico@twosigma.com>
Tue, 14 Apr 2020 10:04:00 +0000 (05:04 -0500)
committerNicolas Williams <nico@twosigma.com>
Tue, 14 Apr 2020 22:00:54 +0000 (17:00 -0500)
.travis.yml
tools/coveralls-tool [new file with mode: 0755]
tools/fixgcov-source-paths.sh [new file with mode: 0755]

index e00616a3c12f9e8dceef804424b911e11b72626d..8961e6a9d278373d98a10fffcfb53301066b2d7c 100644 (file)
@@ -13,21 +13,25 @@ before_install:
     - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get install -qq bison comerr-dev flex libcap-ng-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python ss-dev texinfo unzip netbase keyutils; fi
     - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get install -qq ldap-utils gdb; fi
     - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get install -qq libmicrohttpd-dev; fi
+    - if [ $TRAVIS_OS_NAME = linux -a -n "$COVERAGE" ]; then sudo apt-get install -qq jq; fi
     - if [ $TRAVIS_OS_NAME = osx ]; then brew update; fi
     - if [ $TRAVIS_OS_NAME = osx ]; then brew install cpanm bison flex berkeley-db lmdb openldap openssl; fi
     - if [ $TRAVIS_OS_NAME = osx ]; then sudo cpanm install JSON; fi
+    - if [ $TRAVIS_OS_NAME = osx -a -n "$COVERAGE" ]; then brew install jq; fi
     - mkdir ci-build
     - mkdir coverity-build
     - ./autogen.sh
 
 install:
     - cd ci-build
-    - if [ -n "$COVERAGE" ]; then pip install --user cpp-coveralls; fi
     - |
       if [ $TRAVIS_OS_NAME = osx ]; then
           LDFLAGS="-L/usr/local/opt/berkeley-db/lib -L/usr/local/opt/lmdb/lib" \
           CFLAGS="-I/usr/local/opt/lmdb/include" \
-          ../configure --prefix=/tmp/heimdal \
+          ../configure \
+                  --srcdir=`dirname "$PWD"` \
+                  --prefix=/tmp/heimdal \
+                  --enable-maintainer-mode $COVERAGE \
                   --enable-static=no \
                   --enable-pthread-support \
                   --disable-afs-support \
@@ -38,7 +42,7 @@ install:
                   --with-berkeley-db \
                   --with-berkeley-db-include=/usr/local/opt/berkeley-db/include
       else
-          ../configure --enable-maintainer-mode $COVERAGE
+          ../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode $COVERAGE
       fi
     - ulimit -c unlimited; make -j3
 
@@ -46,7 +50,11 @@ script:
     - if [ x${COVERITY_SCAN_BRANCH} != x1 ]; then ulimit -c unlimited; make check; fi
 
 after_script:
-    - if [ -n "$COVERAGE" ]; then coveralls --gcov-options '\-lp'; fi
+    - |
+      if [ -n "$COVERAGE" ]; then
+          ../tools/coveralls-tool -v -o cov.json -O $PWD -S ..
+          curl -vvvsf -X POST -F "json_file=@cov.json" -F "Filename=json_file" https://coveralls.io/api/v1/jobs
+      fi
 
 after_failure:
     - find . -name test-suite.log -print0 | xargs -0 cat
diff --git a/tools/coveralls-tool b/tools/coveralls-tool
new file mode 100755 (executable)
index 0000000..b185994
--- /dev/null
@@ -0,0 +1,168 @@
+#!/bin/bash
+
+set -euo pipefail
+set +o noglob
+
+PROG=${0##*/}
+
+job=${TRAVIS_JOB_ID:-}
+out=
+incr=false
+repo=
+branch=
+srcdir=$PWD
+objdir=
+token=${COVERALLS_REPO_TOKEN:-}
+verbose=0
+
+function usage {
+    cat <<EOF
+Usage: $PROG [OPTIONS]
+Usage: $PROG [-o FILE] [-S SRCDIR] [-O OBJDIR] [-R URI] [-t TOKEN] [-v] [-x]
+    Options:
+
+     -v         Verbose (on stderr).
+     -x         Trace $PROG
+     -o FILE    Output to FILE instead of stdout.
+     -t TOKEN   Token for Coveralls         (defaults to
+                                             \$COVERALLS_REPO_TOKEN)
+     -J ID      Job ID (e.g., Travis-CI job ID)
+     -S SRCDIR  Path to clone               (defaults to \$PWD)
+     -O OBJDIR  Path to object directory    (defaults to SRCDIR)
+     -R URI     Repository URI              (defaults to origin URI
+                                             for SRCDIR)
+
+    $PROG will look for .gcno and .gcda files in OBJDIR for source files
+    in the clone at SRCDIR and will run gcov on them, and produce
+    a request body as JSON in FILE (or stdout if -o FILE not given)
+    for Coveralls.
+
+    Only C and C++ source files are reported on.  E.g., Yacc/Bison/Flex
+    source files are not reported.
+EOF
+}
+
+while getopts +:J:O:R:S:b:ho:t:vx opt; do
+case "$opt" in
+J) job=$OPTARG;;
+O) cd "$OPTARG"; objdir=$PWD; cd "$OLDPWD";;
+R) repo=$OPTARG;;
+S) cd "$OPTARG"; srcdir=$PWD; cd "$OLDPWD";;
+h) usage 0;;
+b) branch=;;
+i) incr=true;;
+o) out=$OPTARG;;
+t) token=$OPTARG;;
+v) ((verbose++)) || true;;
+x) set -vx;;
+*) usage 1;;
+esac
+done
+
+# Note: we don't cd to $srcdir or $objdir or anywhere, so if $out is a relative
+# path, we do the right thing.
+
+: ${objdir:=${srcdir}}
+: ${repo:=git@github.com:${TRAVIS_REPO_SLUG:-heimdal/heimdal}}
+: ${repo:=$(cd "$srcdir"; git remote get-url origin)}
+: ${branch:=${TRAVIS_BRANCH:-}}
+
+if ((verbose > 1)); then
+    exec 3>&2
+else
+    exec 3>/dev/null
+fi
+
+d=
+function cleanup {
+    [[ -n $d ]] && rm -rf "$d"
+}
+
+trap cleanup EXIT
+d=$(mktemp -d)
+touch "${d}/f"
+
+declare -a gcov
+
+(cd "$srcdir" && git ls-files -- '*.c' '*.cpp') |
+while read f; do
+    # Remember to be careful to refer to ${srcdir}/${f}
+    ((verbose)) && printf 'Processing: %s\n' "$f" 1>&2
+
+    dir=${f%/*}
+    base=${f##*/}
+    base=${base%.*}
+
+    if $incr && [[ -f ${objdir}/${f}.gcov ]]; then
+        true
+    elif [[ -f ${objdir}/${dir}/.libs/${base}.gcda ]]; then
+        ((verbose)) && printf 'Running gcov for %s using gcda from .libs\n' "$f"
+        if ! (cd "${objdir}/${f%/*}"; ((verbose > 1)) && set -vx; gcov -o .libs "${f##*/}") 1>&3; then
+            printf 'Warning: gcov failed for %s\n' "$f" 1>&2
+            continue
+        fi
+    elif ! (cd "${objdir}/${f%/*}"; ((verbose > 1)) && set -vx; gcov "${f##*/}") 1>&3; then
+        printf 'Warning: gcov failed for %s\n' "$f" 1>&2
+        continue
+    fi
+
+    if [[ ! -f ${objdir}/${f}.gcov ]]; then
+        printf 'Warning: gcov did not produce a .gcov file for %s\n' "$f" 1>&2
+        continue
+    fi
+
+    md5=$(md5sum "${srcdir}/${f}")
+    md5=${md5%% *}
+
+    jq -Rn --arg sum "${md5}" --arg f "$f" '
+        {
+            name: $f,
+            source_digest: $sum,
+            coverage: [
+                inputs
+              | split(":")
+              | (.[1] |= tonumber)
+              | select(.[1] > 0)
+              | if .[0]|endswith("#")
+                then 0
+                elif .[0]|endswith("-")
+                then null
+                else .[0]|tonumber
+                end
+            ]
+        }
+    ' "${objdir}/${f}.gcov" >> "${d}/f"
+done
+
+
+[[ -n $out ]] && exec 1>"$out"
+jq -s --arg job "$job" \
+      --arg token "$token" \
+      --arg repo "$repo" \
+      --arg branch "$TRAVIS_BRANCH" \
+      --arg head "$(git log -n1 --format=%H)" \
+      --arg subject "$(git log -n1 --format=%s)" \
+      --arg aN "$(git log -n1 --format=%aN)" \
+      --arg ae "$(git log -n1 --format=%ae)" \
+      --arg cN "$(git log -n1 --format=%cN)" \
+      --arg ce "$(git log -n1 --format=%ce)" \
+    '{
+        service_job_id: $job,
+        service_name: "travis-ci",
+        repo_token: $token,
+        git: {
+            id: $head,
+            author_name:  $aN,
+            author_email: $ae,
+            committer_name:  $cN,
+            committer_email: $ce,
+            message: $subject,
+            branch: $branch,
+            remotes: [ {
+                "name": "origin",
+                "url": $repo
+                }
+            ]
+        },
+        source_files: .
+    }' "${d}/f"
diff --git a/tools/fixgcov-source-paths.sh b/tools/fixgcov-source-paths.sh
new file mode 100755 (executable)
index 0000000..eaa9c9c
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+find ${1:-.} -name '*.gcov' -print | while read f; do
+    case "$f" in
+    */.libs/*) continue;;
+    *) true;;
+    esac
+    echo FIX $f
+    f_basename=${f%%.gcno\#\#*}.c
+    f_basename=${f_basename##*/}
+    head -1 "$f" | grep 'Source:/' > /dev/null && continue
+    #bname=$(head -1 "$f" | grep 'Source:/' | cut -d: -f4)
+    dname=$(echo "$f"|cut -d'#' -f1|sed -e 's,/[^/]*$,/,')
+    ex "$f" <<EOF
+1,1 s,:Source:.*$,:Source:${dname}${f_basename},
+wq!
+EOF
+done