| 1 | #!/usr/bin/env bash |
| 2 | # SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | # shellcheck disable=SC1091,SC2230,SC2086 |
| 4 | # |
| 5 | # Coverity scan script |
| 6 | # |
| 7 | # To run manually, save configuration to .coverity-scan.conf like this: |
| 8 | # |
| 9 | # the repository to report to coverity - devs can set here their own fork |
| 10 | # REPOSITORY="netdata/netdata" |
| 11 | # |
| 12 | # the email of the developer, as given to coverity |
| 13 | # COVERITY_SCAN_SUBMIT_MAIL="you@example.com" |
| 14 | # |
| 15 | # the token given by coverity to the developer |
| 16 | # COVERITY_SCAN_TOKEN="TOKEN taken from Coverity site" |
| 17 | # |
| 18 | # the absolute path of the cov-build - optional |
| 19 | # COVERITY_BUILD_PATH="/opt/cov-analysis-linux64-2021.12/bin/cov-build" |
| 20 | # |
| 21 | # when set, the script will print on screen the curl command that submits the build to coverity |
| 22 | # this includes the token, so the default is not to print it. |
| 23 | # COVERITY_SUBMIT_DEBUG=1 |
| 24 | # |
| 25 | # All these variables can also be exported before running this script. |
| 26 | # |
| 27 | # If the first parameter of this script is "install", |
| 28 | # coverity build tools will be downloaded and installed in /opt/coverity |
| 29 | |
| 30 | set -e |
| 31 | |
| 32 | if [ "$(uname -s)" != "Linux" ] || [ "$(uname -m)" != "x86_64" ]; then |
| 33 | echo "This script can only be used on a 64-bit x86 Linux system." |
| 34 | exit 1 |
| 35 | fi |
| 36 | |
| 37 | INSTALL_DIR="/opt" |
| 38 | |
| 39 | SCRIPT_SOURCE="$( |
| 40 | self=${0} |
| 41 | while [ -L "${self}" ] |
| 42 | do |
| 43 | cd "${self%/*}" || exit 1 |
| 44 | self=$(readlink "${self}") |
| 45 | done |
| 46 | cd "${self%/*}" || exit 1 |
| 47 | echo "$(pwd -P)/${self##*/}" |
| 48 | )" |
| 49 | REPO_ROOT="$(dirname "${SCRIPT_SOURCE}")/../.." |
| 50 | |
| 51 | . "${REPO_ROOT}/packaging/installer/functions.sh" |
| 52 | |
| 53 | JOBS=$(find_processors) |
| 54 | [ -z "${JOBS}" ] && JOBS=1 |
| 55 | |
| 56 | if command -v ninja 2>&1; then |
| 57 | ninja="$(command -v ninja)" |
| 58 | fi |
| 59 | |
| 60 | CMAKE_OPTS="${ninja:+-G Ninja}" |
| 61 | BUILD_OPTS="VERBOSE=1" |
| 62 | [ -n "${ninja}" ] && BUILD_OPTS="-v" |
| 63 | NETDATA_BUILD_DIR="${NETDATA_BUILD_DIR:-./build/}" |
| 64 | |
| 65 | if [ -f ".coverity-scan.conf" ]; then |
| 66 | source ".coverity-scan.conf" |
| 67 | fi |
| 68 | |
| 69 | repo="${REPOSITORY}" |
| 70 | if [ -z "${repo}" ]; then |
| 71 | fatal "export variable REPOSITORY or set it in .coverity-scan.conf" |
| 72 | fi |
| 73 | repo="${repo//\//%2F}" |
| 74 | |
| 75 | email="${COVERITY_SCAN_SUBMIT_MAIL}" |
| 76 | if [ -z "${email}" ]; then |
| 77 | fatal "export variable COVERITY_SCAN_SUBMIT_MAIL or set it in .coverity-scan.conf" |
| 78 | fi |
| 79 | |
| 80 | token="${COVERITY_SCAN_TOKEN}" |
| 81 | if [ -z "${token}" ]; then |
| 82 | fatal "export variable COVERITY_SCAN_TOKEN or set it in .coverity-scan.conf" |
| 83 | fi |
| 84 | |
| 85 | if ! command -v curl > /dev/null 2>&1; then |
| 86 | fatal "CURL is required for coverity scan to work" |
| 87 | fi |
| 88 | |
| 89 | # only print the output of a command |
| 90 | # when debugging is enabled |
| 91 | # used to hide the token when debugging is not enabled |
| 92 | debugrun() { |
| 93 | if [ "${COVERITY_SUBMIT_DEBUG}" = "1" ]; then |
| 94 | run "${@}" |
| 95 | return $? |
| 96 | else |
| 97 | "${@}" |
| 98 | return $? |
| 99 | fi |
| 100 | } |
| 101 | |
| 102 | scanit() { |
| 103 | progress "Scanning using coverity" |
| 104 | COVERITY_PATH=$(find "${INSTALL_DIR}" -maxdepth 1 -name 'cov*linux*') |
| 105 | export PATH=${PATH}:${COVERITY_PATH}/bin/ |
| 106 | covbuild="${COVERITY_BUILD_PATH}" |
| 107 | [ -z "${covbuild}" ] && covbuild="$(which cov-build 2> /dev/null || command -v cov-build 2> /dev/null)" |
| 108 | |
| 109 | if [ -z "${covbuild}" ]; then |
| 110 | fatal "Cannot find 'cov-build' binary in \$PATH. Export variable COVERITY_BUILD_PATH or set it in .coverity-scan.conf" |
| 111 | elif [ ! -x "${covbuild}" ]; then |
| 112 | fatal "The command '${covbuild}' is not executable. Export variable COVERITY_BUILD_PATH or set it in .coverity-scan.conf" |
| 113 | fi |
| 114 | |
| 115 | cd "${REPO_ROOT}" || exit 1 |
| 116 | |
| 117 | version="$(grep "^#define PACKAGE_VERSION" config.h | cut -d '"' -f 2)" |
| 118 | progress "Working on netdata version: ${version}" |
| 119 | |
| 120 | progress "Cleaning up old builds..." |
| 121 | rm -rf "${NETDATA_BUILD_DIR}" |
| 122 | |
| 123 | [ -d "cov-int" ] && rm -rf "cov-int" |
| 124 | |
| 125 | [ -f netdata-coverity-analysis.tgz ] && run rm netdata-coverity-analysis.tgz |
| 126 | |
| 127 | progress "Configuring netdata source..." |
| 128 | USE_SYSTEM_PROTOBUF=1 |
| 129 | ENABLE_GO=0 |
| 130 | prepare_cmake_options |
| 131 | |
| 132 | # shellcheck disable=SC2086 |
| 133 | case "${NETDATA_CMAKE_INSTALL_PREFIX_OPTION:+I}${NETDATA_WINDOWS_PATH_PREFIX_OPTION:+W}" in |
| 134 | "IW") run cmake ${NETDATA_CMAKE_OPTIONS} "${NETDATA_CMAKE_INSTALL_PREFIX_OPTION}" "${NETDATA_WINDOWS_PATH_PREFIX_OPTION}" ;; |
| 135 | "I") run cmake ${NETDATA_CMAKE_OPTIONS} "${NETDATA_CMAKE_INSTALL_PREFIX_OPTION}" ;; |
| 136 | "W") run cmake ${NETDATA_CMAKE_OPTIONS} "${NETDATA_WINDOWS_PATH_PREFIX_OPTION}" ;; |
| 137 | *) run cmake ${NETDATA_CMAKE_OPTIONS} ;; |
| 138 | esac |
| 139 | |
| 140 | progress "Analyzing netdata..." |
| 141 | run "${covbuild}" --dir cov-int cmake --build "${NETDATA_BUILD_DIR}" --parallel ${JOBS} -- ${BUILD_OPTS} |
| 142 | |
| 143 | echo >&2 "Compressing analysis..." |
| 144 | run tar czvf netdata-coverity-analysis.tgz cov-int |
| 145 | |
| 146 | echo >&2 "Sending analysis to coverity for netdata version ${version} ..." |
| 147 | COVERITY_SUBMIT_RESULT=$(debugrun curl --progress-bar \ |
| 148 | --form token="${token}" \ |
| 149 | --form email="${email}" \ |
| 150 | --form file=@netdata-coverity-analysis.tgz \ |
| 151 | --form version="${version}" \ |
| 152 | --form description="netdata, monitor everything, in real-time." \ |
| 153 | https://scan.coverity.com/builds?project="${repo}") |
| 154 | |
| 155 | echo "${COVERITY_SUBMIT_RESULT}" | grep -q -e 'Build successfully submitted' || echo >&2 "scan results were not pushed to coverity. Message was: ${COVERITY_SUBMIT_RESULT}" |
| 156 | |
| 157 | progress "Coverity scan completed" |
| 158 | } |
| 159 | |
| 160 | installit() { |
| 161 | TMP_DIR="$(mktemp -d /tmp/netdata-coverity-scan-XXXXX)" |
| 162 | progress "Downloading coverity in ${TMP_DIR}..." |
| 163 | (cd "${TMP_DIR}" && debugrun curl --remote-name --remote-header-name --show-error --location --data "token=${token}&project=${repo}" https://scan.coverity.com/download/linux64) |
| 164 | |
| 165 | COVERITY_ARCHIVE="$(find "${TMP_DIR}" -maxdepth 1 -mindepth 1 -name 'cov-analysis-linux64-*.tar.gz')" |
| 166 | |
| 167 | if [ -n "${COVERITY_ARCHIVE}" ] && [ -f "${COVERITY_ARCHIVE}" ]; then |
| 168 | progress "Installing coverity..." |
| 169 | run sudo tar -z -x -f "${COVERITY_ARCHIVE}" -C "${INSTALL_DIR}" |
| 170 | rm -f "${COVERITY_ARCHIVE}" |
| 171 | COVERITY_PATH=$(find "${INSTALL_DIR}" -maxdepth 1 -name 'cov*linux*') |
| 172 | export PATH="${PATH}:${COVERITY_PATH}/bin/" |
| 173 | elif find "${TMP_DIR}" -name "*.tar.gz" > /dev/null 2>&1; then |
| 174 | ls "${TMP_DIR}"/*.tar.gz |
| 175 | fatal "Downloaded coverity tool tarball does not appear to be the file-name we were expecting, exiting." |
| 176 | else |
| 177 | fatal "Failed to download coverity tool tarball!" |
| 178 | fi |
| 179 | |
| 180 | # Validate the installation |
| 181 | covbuild="$(which cov-build 2> /dev/null || command -v cov-build 2> /dev/null)" |
| 182 | if [ -z "$covbuild" ]; then |
| 183 | fatal "Failed to install coverity." |
| 184 | fi |
| 185 | |
| 186 | progress "Coverity scan tools are installed." |
| 187 | |
| 188 | # Clean temp directory |
| 189 | [ -n "${TMP_DIR}" ] && rm -rf "${TMP_DIR}" |
| 190 | return 0 |
| 191 | } |
| 192 | |
| 193 | FOUND_OPTS="NO" |
| 194 | while [ -n "${1}" ]; do |
| 195 | if [ "${1}" = "--with-install" ]; then |
| 196 | progress "Running coverity install" |
| 197 | installit |
| 198 | shift 1 |
| 199 | elif [ -n "${1}" ]; then |
| 200 | # Clear the default arguments, once you bump into the first argument |
| 201 | if [ "${FOUND_OPTS}" = "NO" ]; then |
| 202 | OTHER_OPTIONS="${1}" |
| 203 | FOUND_OPTS="YES" |
| 204 | else |
| 205 | OTHER_OPTIONS+=" ${1}" |
| 206 | fi |
| 207 | |
| 208 | shift 1 |
| 209 | else |
| 210 | break |
| 211 | fi |
| 212 | done |
| 213 | |
| 214 | echo "Running coverity scan with extra options ${OTHER_OPTIONS}" |
| 215 | scanit "${OTHER_OPTIONS}" |