summaryrefslogtreecommitdiffstats
path: root/packaging/utils/coverity-scan.sh
blob: ebb82102d531643d8a2f7c204e586c3e54840f93 (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
#!/usr/bin/env bash
#
# Coverity scan script
#
# Copyright: SPDX-License-Identifier: GPL-3.0-or-later
#
# Author  : Costa Tsaousis (costa@netdata.cloud)
# Author  : Pawel Krupa (paulfantom)
# Author  : Pavlos Emm. Katsoulakis (paul@netdata.cloud)
# shellcheck disable=SC1091,SC2230,SC2086

# To run manually, save configuration to .coverity-scan.conf like this:
#
# the repository to report to coverity - devs can set here their own fork
# REPOSITORY="netdata/netdata"
#
# the email of the developer, as given to coverity
# COVERITY_SCAN_SUBMIT_MAIL="you@example.com"
#
# the token given by coverity to the developer
# COVERITY_SCAN_TOKEN="TOKEN taken from Coverity site"
#
# the absolute path of the cov-build - optional
# COVERITY_BUILD_PATH="/opt/cov-analysis-linux64-2021.12/bin/cov-build"
#
# when set, the script will print on screen the curl command that submits the build to coverity
# this includes the token, so the default is not to print it.
# COVERITY_SUBMIT_DEBUG=1
#
# All these variables can also be exported before running this script.
#
# If the first parameter of this script is "install",
# coverity build tools will be downloaded and installed in /opt/coverity

set -e

if [ "$(uname -s)" != "Linux" ] || [ "$(uname -m)" != "x86_64" ]; then
  echo "This script can only be used on a 64-bit x86 Linux system."
  exit 1
fi

INSTALL_DIR="/opt"

SCRIPT_SOURCE="$(
    self=${0}
    while [ -L "${self}" ]
    do
        cd "${self%/*}" || exit 1
        self=$(readlink "${self}")
    done
    cd "${self%/*}" || exit 1
    echo "$(pwd -P)/${self##*/}"
)"
REPO_ROOT="$(dirname "${SCRIPT_SOURCE}")/../.."

. "${REPO_ROOT}/packaging/installer/functions.sh"

JOBS=$(find_processors)
[ -z "${JOBS}" ] && JOBS=1

if command -v ninja 2>&1; then
    ninja="$(command -v ninja)"
fi

CMAKE_OPTS="${ninja:+-G Ninja}"
BUILD_OPTS="VERBOSE=1"
[ -n "${ninja}" ] && BUILD_OPTS="-v"
NETDATA_BUILD_DIR="${NETDATA_BUILD_DIR:-./build/}"

if [ -f ".coverity-scan.conf" ]; then
  source ".coverity-scan.conf"
fi

repo="${REPOSITORY}"
if [ -z "${repo}" ]; then
  fatal "export variable REPOSITORY or set it in .coverity-scan.conf"
fi
repo="${repo//\//%2F}"

email="${COVERITY_SCAN_SUBMIT_MAIL}"
if [ -z "${email}" ]; then
  fatal "export variable COVERITY_SCAN_SUBMIT_MAIL or set it in .coverity-scan.conf"
fi

token="${COVERITY_SCAN_TOKEN}"
if [ -z "${token}" ]; then
  fatal "export variable COVERITY_SCAN_TOKEN or set it in .coverity-scan.conf"
fi

if ! command -v curl > /dev/null 2>&1; then
  fatal "CURL is required for coverity scan to work"
fi

# only print the output of a command
# when debugging is enabled
# used to hide the token when debugging is not enabled
debugrun() {
  if [ "${COVERITY_SUBMIT_DEBUG}" = "1" ]; then
    run "${@}"
    return $?
  else
    "${@}"
    return $?
  fi
}

scanit() {
  progress "Scanning using coverity"
  COVERITY_PATH=$(find "${INSTALL_DIR}" -maxdepth 1 -name 'cov*linux*')
  export PATH=${PATH}:${COVERITY_PATH}/bin/
  covbuild="${COVERITY_BUILD_PATH}"
  [ -z "${covbuild}" ] && covbuild="$(which cov-build 2> /dev/null || command -v cov-build 2> /dev/null)"

  if [ -z "${covbuild}" ]; then
    fatal "Cannot find 'cov-build' binary in \$PATH. Export variable COVERITY_BUILD_PATH or set it in .coverity-scan.conf"
  elif [ ! -x "${covbuild}" ]; then
    fatal "The command '${covbuild}' is not executable. Export variable COVERITY_BUILD_PATH or set it in .coverity-scan.conf"
  fi

  cd "${REPO_ROOT}" || exit 1

  version="$(grep "^#define PACKAGE_VERSION" config.h | cut -d '"' -f 2)"
  progress "Working on netdata version: ${version}"

  progress "Cleaning up old builds..."
  rm -rf "${NETDATA_BUILD_DIR}"

  [ -d "cov-int" ] && rm -rf "cov-int"

  [ -f netdata-coverity-analysis.tgz ] && run rm netdata-coverity-analysis.tgz

  progress "Configuring netdata source..."
  USE_SYSTEM_PROTOBUF=1
  ENABLE_GO=0
  prepare_cmake_options

  run cmake ${NETDATA_CMAKE_OPTIONS}

  progress "Analyzing netdata..."
  run "${covbuild}" --dir cov-int cmake --build "${NETDATA_BUILD_DIR}" --parallel ${JOBS} -- ${BUILD_OPTS}

  echo >&2 "Compressing analysis..."
  run tar czvf netdata-coverity-analysis.tgz cov-int

  echo >&2 "Sending analysis to coverity for netdata version ${version} ..."
  COVERITY_SUBMIT_RESULT=$(debugrun curl --progress-bar \
    --form token="${token}" \
    --form email="${email}" \
    --form file=@netdata-coverity-analysis.tgz \
    --form version="${version}" \
    --form description="netdata, monitor everything, in real-time." \
    https://scan.coverity.com/builds?project="${repo}")

  echo "${COVERITY_SUBMIT_RESULT}" | grep -q -e 'Build successfully submitted' || echo >&2 "scan results were not pushed to coverity. Message was: ${COVERITY_SUBMIT_RESULT}"

  progress "Coverity scan completed"
}

installit() {
  TMP_DIR="$(mktemp -d /tmp/netdata-coverity-scan-XXXXX)"
  progress "Downloading coverity in ${TMP_DIR}..."
  (cd "${TMP_DIR}" && debugrun curl --remote-name --remote-header-name --show-error --location --data "token=${token}&project=${repo}" https://scan.coverity.com/download/linux64)

  COVERITY_ARCHIVE="$(find  "${TMP_DIR}" -maxdepth 1 -mindepth 1 -name 'cov-analysis-linux64-*.tar.gz')"

  if [ -n "${COVERITY_ARCHIVE}" ] && [ -f "${COVERITY_ARCHIVE}" ]; then
    progress "Installing coverity..."
    run sudo tar -z -x -f "${COVERITY_ARCHIVE}" -C "${INSTALL_DIR}"
    rm -f "${COVERITY_ARCHIVE}"
    COVERITY_PATH=$(find "${INSTALL_DIR}" -maxdepth 1 -name 'cov*linux*')
    export PATH="${PATH}:${COVERITY_PATH}/bin/"
  elif find "${TMP_DIR}" -name "*.tar.gz" > /dev/null 2>&1; then
    ls "${TMP_DIR}"/*.tar.gz
    fatal "Downloaded coverity tool tarball does not appear to be the file-name we were expecting, exiting."
  else
    fatal "Failed to download coverity tool tarball!"
  fi

  # Validate the installation
  covbuild="$(which cov-build 2> /dev/null || command -v cov-build 2> /dev/null)"
  if [ -z "$covbuild" ]; then
    fatal "Failed to install coverity."
  fi

  progress "Coverity scan tools are installed."

  # Clean temp directory
  [ -n "${TMP_DIR}" ] && rm -rf "${TMP_DIR}"
  return 0
}

FOUND_OPTS="NO"
while [ -n "${1}" ]; do
  if [ "${1}" = "--with-install" ]; then
    progress "Running coverity install"
    installit
    shift 1
  elif [ -n "${1}" ]; then
    # Clear the default arguments, once you bump into the first argument
    if [ "${FOUND_OPTS}" = "NO" ]; then
      OTHER_OPTIONS="${1}"
      FOUND_OPTS="YES"
    else
      OTHER_OPTIONS+=" ${1}"
    fi

    shift 1
  else
    break
  fi
done

echo "Running coverity scan with extra options ${OTHER_OPTIONS}"
scanit "${OTHER_OPTIONS}"