diff --git a/.travis.yml b/.travis.yml index 8961e6a9d..0db7432b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,11 +50,7 @@ script: - if [ x${COVERITY_SCAN_BRANCH} != x1 ]; then ulimit -c unlimited; make check; fi after_script: - - | - 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 + - if [ -n "$COVERAGE" ]; then ../tools/coveralls-tool -O $PWD -S ..; fi after_failure: - find . -name test-suite.log -print0 | xargs -0 cat diff --git a/tools/coveralls-tool b/tools/coveralls-tool index 863c9896d..981bd1757 100755 --- a/tools/coveralls-tool +++ b/tools/coveralls-tool @@ -1,5 +1,27 @@ #!/bin/bash +# This script collates gcov data after one has configured with --enable-gcov, +# built, and run tests. It either outputs or POSTs to Coveralls a JSON text in +# the schema for the Coveralls API, which is documented here: +# +# https://docs.coveralls.io/api-introduction +# https://docs.coveralls.io/api-reference +# +# Currently only files in source languages supported by gcov(1) are reported +# on, though this can easily be extended. Currently that's only C/C++ files. +# +# This script is specifically written for Heimdal, which is an open source C +# codebases that uses autoconf and libtool for its build system. This means +# that sometimes the gcov notes and data files are not necessarily where the +# gcov(1) utility would find them, which is why this script exists instead of +# using some other integration script. +# +# Although this is specific to Heimdal, it can be extended. +# +# Note that one side effect of running this script, gcov(1) will be run for all +# C/C++ source files in the workspace. As well, some gcov notes and data files +# maybe hard-linked to other names. However, this script should be idempotent. + set -euo pipefail set +o noglob @@ -7,54 +29,87 @@ PROG=${0##*/} job=${TRAVIS_JOB_ID:-} out= -incr=false +post=false repo= +flst= +quiet=false branch= srcdir=$PWD objdir= token=${COVERALLS_REPO_TOKEN:-} +origin= verbose=0 function usage { + ((${1:-1})) && exec 1>&2 cat < 3)) && set -vx;; *) usage 1;; esac done @@ -63,9 +118,27 @@ done # 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:-}} +: ${branch:=${TRAVIS_BRANCH:-$(cd "$srcdir" && git rev-parse --abbrev-ref HEAD)}} + +if [[ -z ${origin:-} ]]; then + origin=$( + git for-each-ref \ + --format="%(refname:short) %(upstream:remotename)" refs/heads | + while read gb gr; do + [[ $gb = $branch ]] || continue + printf '%s\n' "$gr" + break + done + ) +fi + +if [[ -z ${repo:-} ]]; then + if [[ -n ${TRAVIS_REPO_SLUG:-} ]]; then + repo=git@github.com:${TRAVIS_REPO_SLUG:-heimdal/heimdal} + else + repo=$(cd "$srcdir" && git remote get-url --push "$origin") + fi +fi if ((verbose > 1)); then exec 3>&2 @@ -84,7 +157,8 @@ touch "${d}/f" declare -a gcov -(cd "$srcdir" && git ls-files -- '*.c' '*.cpp') | +(cd "$srcdir" && + if [[ -n $flst ]]; then cat "$flst"; else git ls-files -- '*.c' '*.cpp'; fi) | while read f; do # Remember to be careful to refer to ${srcdir}/${f} ((verbose)) && printf 'Processing: %s\n' "$f" 1>&2 @@ -107,28 +181,26 @@ while read f; do [[ -n $gcno && -f $gcno ]] && ln -f "$gcno" "${objdir}/${dir}/.libs/${base}.gcno" [[ -n $gcda && -f $gcda ]] && ln -f "$gcda" "${objdir}/${dir}/.libs/${base}.gcda" if [[ ( -n $gcda && ! -f $gcda ) || ( -n $gcno && ! -f $gcno ) ]]; then - ((verbose)) && printf 'Warning: %s has no gcov notes file\n' "$f" 1>&3 + $quiet || printf 'Warning: %s has no gcov notes file\n' "$f" 1>&2 continue fi fi - 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 + if [[ -f ${objdir}/${dir}/.libs/${base}.gcda ]]; then + ((verbose > 1)) && printf 'Running gcov for %s using gcda from .libs\n' "$f" 1>&2 + if ! (cd "${objdir}/${f%/*}"; ((verbose > 2)) && set -vx; gcov -o .libs "${f##*/}") 1>&3; then + $quiet || printf 'Warning: gcov failed for %s\n' "$f" 1>&2 continue fi elif [[ -f ${objdir}/${dir}/${base}.gcda ]]; then - if ! (cd "${objdir}/${f%/*}"; ((verbose > 1)) && set -vx; gcov "${f##*/}") 1>&3; then - printf 'Warning: gcov failed for %s\n' "$f" 1>&2 + if ! (cd "${objdir}/${f%/*}"; ((verbose > 2)) && set -vx; gcov "${f##*/}") 1>&3; then + $quiet || printf 'Warning: gcov failed for %s\n' "$f" 1>&2 continue fi fi if [[ ! -f ${objdir}/${f}.gcov ]]; then - printf 'Warning: gcov did not produce a .gcov file for %s\n' "$f" 1>&2 + $quiet || printf 'Warning: gcov did not produce a .gcov file for %s\n' "$f" 1>&2 continue fi @@ -155,35 +227,51 @@ while read f; do ' "${objdir}/${f}.gcov" >> "${d}/f" done +function make_report { + jq -s --arg job "$job" \ + --arg ci "${ci:-travis-ci}" \ + --arg token "$token" \ + --arg repo "$repo" \ + --arg branch "$branch" \ + --arg upstream "$origin" \ + --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: $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": $upstream, + "url": $repo + } + ] + }, + source_files: . + }' "${d}/f" +} -[[ -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" +if [[ -z $out ]]; then + post=true + make_report > "${d}/out" +elif [[ $out = - ]]; then + make_report +else + make_report > "${out}" +fi + +if $post && [[ $out != /dev/stdout ]]; then + curl -sfg -X POST -F "json_file=@${d}/out" -F "Filename=json_file" \ + https://coveralls.io/api/v1/jobs +fi