summaryrefslogtreecommitdiff
path: root/tools/coverity.sh
blob: e32f5b3993b68eabfb53de1d3166a1e06e935a91 (plain)
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!/bin/bash

# The official unmodified version of the script can be found at
# https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh

set -e

# Declare build command
COVERITY_SCAN_BUILD_COMMAND="ninja -C cov-build"

# Environment check
# Use default values if not set
SCAN_URL=${SCAN_URL:="https://scan.coverity.com"}
TOOL_BASE=${TOOL_BASE:="/tmp/coverity-scan-analysis"}
UPLOAD_URL=${UPLOAD_URL:="https://scan.coverity.com/builds"}

# These must be set by environment
echo -e "\033[33;1mNote: COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN are available on Project Settings page on scan.coverity.com\033[0m"
[ -z "$COVERITY_SCAN_PROJECT_NAME" ] && echo "ERROR: COVERITY_SCAN_PROJECT_NAME must be set" && exit 1
[ -z "$COVERITY_SCAN_NOTIFICATION_EMAIL" ] && echo "ERROR: COVERITY_SCAN_NOTIFICATION_EMAIL must be set" && exit 1
[ -z "$COVERITY_SCAN_BRANCH_PATTERN" ] && echo "ERROR: COVERITY_SCAN_BRANCH_PATTERN must be set" && exit 1
[ -z "$COVERITY_SCAN_BUILD_COMMAND" ] && echo "ERROR: COVERITY_SCAN_BUILD_COMMAND must be set" && exit 1
[ -z "$COVERITY_SCAN_TOKEN" ] && echo "ERROR: COVERITY_SCAN_TOKEN must be set" && exit 1

# Do not run on pull requests
if [ "${TRAVIS_PULL_REQUEST}" = "true" ]; then
    echo -e "\033[33;1mINFO: Skipping Coverity Analysis: branch is a pull request.\033[0m"
    exit 0
fi

# Verify this branch should run
if [[ "${TRAVIS_BRANCH^^}" =~ "${COVERITY_SCAN_BRANCH_PATTERN^^}" ]]; then
    echo -e "\033[33;1mCoverity Scan configured to run on branch ${TRAVIS_BRANCH}\033[0m"
else
    echo -e "\033[33;1mCoverity Scan NOT configured to run on branch ${TRAVIS_BRANCH}\033[0m"
    exit 1
fi

# Verify upload is permitted
AUTH_RES=`curl -s --form project="$COVERITY_SCAN_PROJECT_NAME" --form token="$COVERITY_SCAN_TOKEN" $SCAN_URL/api/upload_permitted`
if [ "$AUTH_RES" = "Access denied" ]; then
    echo -e "\033[33;1mCoverity Scan API access denied. Check COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN.\033[0m"
    exit 1
else
    AUTH=`echo $AUTH_RES | python -c "import sys, json; print(json.load(sys.stdin)['upload_permitted'])"`
    if [ "$AUTH" = "True" ]; then
        echo -e "\033[33;1mCoverity Scan analysis authorized per quota.\033[0m"
    else
        WHEN=`echo $AUTH_RES | python -c "import sys, json; print(json.load(sys.stdin)['next_upload_permitted_at'])"`
        echo -e "\033[33;1mCoverity Scan analysis NOT authorized until $WHEN.\033[0m"
        exit 1
    fi
fi

TOOL_DIR=`find $TOOL_BASE -type d -name 'cov-analysis*'`
export PATH="$TOOL_DIR/bin:$PATH"

# Disable CCACHE for cov-build to compilation units correctly
export CCACHE_DISABLE=1

# FUNCTION DEFINITIONS
# --------------------
_help()
{
    # displays help and exits
    cat <<-EOF
		USAGE: $0 [CMD] [OPTIONS]

		CMD
		  build   Issue Coverity build
		  upload  Upload coverity archive for analysis
              Note: By default, archive is created from default results directory.
                    To provide custom archive or results directory, see --result-dir
                    and --tar options below.

		OPTIONS
		  -h,--help     Display this menu and exits

		  Applicable to build command
		  ---------------------------
		  -o,--out-dir  Specify Coverity intermediate directory (defaults to 'cov-int')
		  -t,--tar      bool, archive the output to .tgz file (defaults to false)

		  Applicable to upload command
		  ----------------------------
		  -d, --result-dir   Specify result directory if different from default ('cov-int')
		  -t, --tar ARCHIVE  Use custom .tgz archive instead of intermediate directory or pre-archived .tgz
                         (by default 'analysis-result.tgz'
	EOF
    return;
}

_pack()
{
    RESULTS_ARCHIVE=${RESULTS_ARCHIVE:-'analysis-results.tgz'}

    echo -e "\033[33;1mTarring Coverity Scan Analysis results...\033[0m"
    tar czf $RESULTS_ARCHIVE $RESULTS_DIR
    SHA=`git rev-parse --short HEAD`

    PACKED=true
}


_build()
{
    echo -e "\033[33;1mRunning Coverity Scan Analysis Tool...\033[0m"
    local _cov_build_options=""
    #local _cov_build_options="--return-emit-failures 8 --parse-error-threshold 85"
    eval "${COVERITY_SCAN_BUILD_COMMAND_PREPEND}"
    COVERITY_UNSUPPORTED=1 cov-build --dir $RESULTS_DIR $_cov_build_options sh -c "$COVERITY_SCAN_BUILD_COMMAND"
    cov-import-scm --dir $RESULTS_DIR --scm git --log $RESULTS_DIR/scm_log.txt

    if [ $? != 0 ]; then
	echo -e "\033[33;1mCoverity Scan Build failed: $TEXT.\033[0m"
	return 1
    fi

    [ -z $TAR ] || [ $TAR = false ] && return 0

    if [ "$TAR" = true ]; then
	_pack
    fi
}


_upload()
{
    # pack results
    [ -z $PACKED ] || [ $PACKED = false ] && _pack

    # Upload results
    echo -e "\033[33;1mUploading Coverity Scan Analysis results...\033[0m"
    response=$(curl \
	           --silent --write-out "\n%{http_code}\n" \
	           --form project=$COVERITY_SCAN_PROJECT_NAME \
	           --form token=$COVERITY_SCAN_TOKEN \
	           --form email=$COVERITY_SCAN_NOTIFICATION_EMAIL \
	           --form file=@$RESULTS_ARCHIVE \
	           --form version=$SHA \
	           --form description="Travis CI build" \
	           $UPLOAD_URL)
    printf "\033[33;1mThe response is\033[0m\n%s\n" "$response"
    status_code=$(echo "$response" | sed -n '$p')
    # Coverity Scan used to respond with 201 on successfully receiving analysis results.
    # Now for some reason it sends 200 and may change back in the foreseeable future.
    # See https://github.com/pmem/pmdk/commit/7b103fd2dd54b2e5974f71fb65c81ab3713c12c5
    if [ "$status_code" != "200" ]; then
	TEXT=$(echo "$response" | sed '$d')
	echo -e "\033[33;1mCoverity Scan upload failed: $TEXT.\033[0m"
	exit 1
    fi

    echo -e "\n\033[33;1mCoverity Scan Analysis completed successfully.\033[0m"
    exit 0
}

# PARSE COMMAND LINE OPTIONS
# --------------------------

case $1 in
    -h|--help)
	_help
	exit 0
	;;
    build)
	CMD='build'
	TEMP=`getopt -o ho:t --long help,out-dir:,tar -n '$0' -- "$@"`
	_ec=$?
	[[ $_ec -gt 0 ]] && _help && exit $_ec
	shift
	;;
    upload)
	CMD='upload'
	TEMP=`getopt -o hd:t: --long help,result-dir:tar: -n '$0' -- "$@"`
	_ec=$?
	[[ $_ec -gt 0 ]] && _help && exit $_ec
	shift
	;;
    *)
	_help && exit 1 ;;
esac

RESULTS_DIR='cov-int'

eval set -- "$TEMP"
if [ $? != 0 ] ; then exit 1 ; fi

# extract options and their arguments into variables.
if [[ $CMD == 'build' ]]; then
    TAR=false
    while true ; do
	case $1 in
	    -h|--help)
		_help
		exit 0
		;;
	    -o|--out-dir)
		RESULTS_DIR="$2"
		shift 2
		;;
	    -t|--tar)
		TAR=true
		shift
		;;
	    --) _build; shift ; break ;;
	    *) echo "Internal error" ; _help && exit 6 ;;
	esac
    done

elif [[ $CMD == 'upload' ]]; then
    while true ; do
	case $1 in
	    -h|--help)
		_help
		exit 0
		;;
	    -d|--result-dir)
		CHANGE_DEFAULT_DIR=true
		RESULTS_DIR="$2"
		shift 2
		;;
	    -t|--tar)
		RESULTS_ARCHIVE="$2"
		[ -z $CHANGE_DEFAULT_DIR ] || [ $CHANGE_DEFAULT_DIR = false ] && PACKED=true
		shift 2
		;;
	    --) _upload; shift ; break ;;
	    *) echo "Internal error" ; _help && exit 6 ;;
	esac
    done

fi