Fathi Boudra | 422bf77 | 2019-12-02 11:10:16 +0200 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | # |
| 3 | # Copyright (c) 2019, Arm Limited. All rights reserved. |
| 4 | # |
| 5 | # SPDX-License-Identifier: BSD-3-Clause |
| 6 | # |
| 7 | |
| 8 | # This file is sourced from the build_package.sh script to use |
| 9 | # coverity_wrapper() function as a build wrapper. |
| 10 | # |
| 11 | # This wrapper supports two work flows: |
| 12 | # |
| 13 | # - Compare the branch under test with that of master, and print defects. If |
| 14 | # there are defects, we arrange the build to be marked as unstable. Set |
| 15 | # $cov_run_type to 'branch-report-compare' to use this. |
| 16 | # |
| 17 | # - Commit and create snapshot for the entire branch. Set $cov_run_type to |
| 18 | # 'branch-report-full' to use this. |
| 19 | # |
| 20 | # Coverity analysis involves contacting the server, which have shown to be very |
| 21 | # slow. Depending on the type of analysis performed, we might have to do |
| 22 | # analysis more than once, and doing that in series would only increase the turn |
| 23 | # around time. To mitigate this, all Coverity commands are saved as small |
| 24 | # snippets, and are then called from a Makefile. Make take care of running |
| 25 | # commands in parallel (all this at the expense of readability). |
| 26 | |
| 27 | coverity_wrapper() { |
| 28 | local cov_dir="$workspace/coverity" |
| 29 | local cov_config="$cov_dir/config" |
| 30 | local cov_compiler="${cov_compiler:-${CROSS_COMPILE}gcc}" |
| 31 | |
| 32 | local golden_repo="$cov_dir/golden-repo" |
| 33 | local golden_snapshot="$cov_dir/golden-snapshot" |
| 34 | |
| 35 | local branch_repo="$cov_dir/branch-repo" |
| 36 | local branch_snapshot="$cov_dir/branch-snapshot" |
| 37 | |
| 38 | local auth_file="${cov_auth_file:-$ci_root/coverity/tfcibot@$coverity_host}" |
| 39 | local makefile="$workspace/makefile.cov" |
| 40 | local snippets_dir="$cov_dir/snippets" |
| 41 | local stream_name="${BUILD_CONFIG:?}" |
| 42 | |
| 43 | local ref_arg |
| 44 | local description |
| 45 | local need_compare |
| 46 | |
| 47 | echo_w |
| 48 | mkdir -p "$cov_dir" |
| 49 | |
| 50 | if echo "${cov_run_type:?}" | grep -iq "branch-report-compare"; then |
| 51 | need_compare=1 |
| 52 | local golden_url="${cov_golden_url:-$tf_src_repo_url}" |
| 53 | local golden_ref="${cov_golden_ref:-master}" |
| 54 | fi |
| 55 | |
| 56 | if upon "$local_ci"; then |
| 57 | description="$USER-local ${cov_checker:?}" |
| 58 | # Reference repository can't be shallow |
| 59 | if [ ! -f "$tf_root/.git/shallow" ]; then |
| 60 | ref_arg="--reference $tf_root" |
| 61 | fi |
| 62 | else |
| 63 | description="$JOB_NAME#$BUILD_NUMBER ${cov_checker:?}" |
| 64 | ref_arg="--reference $project_filer/ref-repos/trusted-firmware" |
| 65 | fi |
| 66 | |
| 67 | # Create a stream and assign to Trusted Firmware project |
| 68 | chmod 400 "$auth_file" |
| 69 | |
| 70 | mkdir -p "$snippets_dir" |
| 71 | cat <<EOF >"$makefile" |
| 72 | SHELL := /bin/bash |
| 73 | |
| 74 | define run-snippet |
| 75 | echo ":\$@" >&3 |
| 76 | echo ">\$@: \$\$(date)" |
| 77 | if ! bash -ex $snippets_dir/\$@; then \\ |
| 78 | echo " :\$@ failed! See build log" >&3; \\ |
| 79 | exit 1; \\ |
| 80 | fi |
| 81 | echo "<\$@: \$\$(date)" |
| 82 | endef |
| 83 | |
| 84 | EOF |
| 85 | |
| 86 | create_snippet() { |
| 87 | # Create a script snippet |
| 88 | cat >"$snippets_dir/${name?}" |
| 89 | |
| 90 | # Add a rule to the makefile |
| 91 | cat <<EOF >>"$makefile" |
| 92 | $name:${deps:+ $deps} |
| 93 | @\$(run-snippet) |
| 94 | |
| 95 | EOF |
| 96 | } |
| 97 | |
| 98 | # golden-setup. Additionally query for a snapshot ID corresponding to |
| 99 | # this version in the stream. If a snapshot ID exists, the comparison |
| 100 | # file is generated containing the snapshot ID. |
| 101 | # |
| 102 | # We need to make a shallow clone of the repository first in order to |
| 103 | # get the reference, however. And, if later we find needing a fresh |
| 104 | # snapshot, we unshallow that. |
| 105 | cat <<EOF | name="golden-setup" create_snippet |
| 106 | git clone --depth 1 -q $ref_arg "$golden_url" "$golden_repo" |
| 107 | cd -P "$golden_repo" |
| 108 | git fetch --depth 1 -q origin "$golden_ref" |
| 109 | git checkout -q FETCH_HEAD |
| 110 | |
| 111 | if [ -z "$cov_force_commit" ]; then |
| 112 | "$ci_root/script/get_latest_snapshot.py" \\ |
| 113 | --host "$coverity_host" \\ |
Zelalem | 219df41 | 2020-05-17 19:21:20 -0500 | [diff] [blame] | 114 | --https-port "$coverity_port" \\ |
Fathi Boudra | 422bf77 | 2019-12-02 11:10:16 +0200 | [diff] [blame] | 115 | --file "$golden_snapshot" \\ |
| 116 | --description "*$cov_checker*" \\ |
| 117 | --version "\$(git show -q --format=%H)" \\ |
| 118 | "$stream_name" 2>&3 || true |
| 119 | fi |
| 120 | |
| 121 | { |
| 122 | echo " golden: $golden_url $golden_ref" |
| 123 | echo " golden: \$(git show -q --format=%H)" |
| 124 | } >&3 |
| 125 | |
| 126 | if [ -f "$golden_snapshot" ]; then |
| 127 | echo " golden: snapshot ID \$(cat $golden_snapshot) exists" >&3 |
| 128 | else |
| 129 | git fetch -q --unshallow origin |
| 130 | fi |
| 131 | EOF |
| 132 | |
| 133 | |
| 134 | # Setup branch |
| 135 | if upon "$local_ci"; then |
| 136 | if not_upon "$need_compare"; then |
| 137 | ln -s "$tf_root" "$branch_repo" |
| 138 | |
| 139 | # Run scanning as-is since we don't need a comparison. |
| 140 | cat <<EOF | name="branch-setup" create_snippet |
| 141 | if [ "$dont_clean" != 1 ]; then |
| 142 | cd -P "$branch_repo" |
| 143 | MAKEFLAGS= make distclean |
| 144 | fi |
| 145 | EOF |
| 146 | else |
| 147 | # Running comparison means that we need to make a merge |
| 148 | # commit. It's undesirable to do that on the user's |
| 149 | # working copy, so do it on a separate one. |
| 150 | cat <<EOF | name="branch-setup" create_snippet |
| 151 | git clone -q $ref_arg "$tf_src_repo_url" "$branch_repo" |
| 152 | cd -P "$branch_repo" |
| 153 | git checkout -b cov-branch origin/master |
| 154 | rsync -a --exclude=".git" --exclude "**.o" --exclude "**.d" "$tf_root/" . |
| 155 | git add . |
| 156 | git -c user.useconfigonly=false commit --allow-empty -q -m "Test branch" |
| 157 | git checkout master |
| 158 | git -c user.useconfigonly=false merge --no-ff -q cov-branch |
| 159 | |
| 160 | git remote add golden "$golden_url" |
| 161 | git fetch -q golden "$golden_ref" |
| 162 | git checkout -q -b cov-golden FETCH_HEAD |
| 163 | git -c user.useconfigonly=false merge --no-edit --no-ff -q cov-branch |
| 164 | EOF |
| 165 | fi |
| 166 | else |
| 167 | # Use the local checkout at $tf_root for analysing branch and |
| 168 | # golden together |
| 169 | ln -s "$tf_root" "$branch_repo" |
| 170 | |
| 171 | cat <<EOF | name="branch-setup" create_snippet |
| 172 | if [ "$need_compare" ]; then |
| 173 | cd -P "$branch_repo" |
| 174 | if [ -f ".git/shallow" ]; then |
| 175 | git fetch -q --unshallow origin |
| 176 | fi |
| 177 | git remote add golden "$golden_url" |
| 178 | git fetch -q golden $golden_ref |
| 179 | git branch cov-branch HEAD |
| 180 | git checkout -q -b cov-golden FETCH_HEAD |
| 181 | echo " branch: \$(git show -q --format=%H cov-branch)" >&3 |
| 182 | git -c user.useconfigonly=false merge --no-edit --no-ff -q cov-branch |
| 183 | fi |
| 184 | EOF |
| 185 | fi |
| 186 | |
| 187 | |
| 188 | # Setup stream |
| 189 | cat <<EOF | name="stream-setup" create_snippet |
| 190 | if cov-manage-im --mode streams --add --set "name:$stream_name" \\ |
| 191 | --auth-key-file "$auth_file" \\ |
Zelalem | 219df41 | 2020-05-17 19:21:20 -0500 | [diff] [blame] | 192 | --host "$coverity_host" --ssl --port "$coverity_port"; then |
Fathi Boudra | 422bf77 | 2019-12-02 11:10:16 +0200 | [diff] [blame] | 193 | cov-manage-im --mode projects --name "Arm Trusted Firmware" --update \\ |
| 194 | --insert "stream:$stream_name" --auth-key-file "$auth_file" \\ |
Zelalem | 219df41 | 2020-05-17 19:21:20 -0500 | [diff] [blame] | 195 | --host "$coverity_host" --ssl --port "$coverity_port" |
Fathi Boudra | 422bf77 | 2019-12-02 11:10:16 +0200 | [diff] [blame] | 196 | fi |
| 197 | EOF |
| 198 | |
| 199 | |
| 200 | # Coverity configuration |
| 201 | cat <<EOF | name="cov-config" create_snippet |
| 202 | cov-configure --comptype gcc --template --compiler "$cov_compiler" \\ |
| 203 | --config "$cov_config/config.xml" |
| 204 | EOF |
| 205 | |
| 206 | |
| 207 | # cov-build on golden; only performed if a comparison file doesn't |
| 208 | # exist. |
| 209 | cat <<EOF | name="golden-cov-build" deps="cov-config golden-setup" \ |
| 210 | create_snippet |
| 211 | if [ ! -f "$golden_snapshot" -o -n "$cov_force_commit" ]; then |
| 212 | cd -P "$golden_repo" |
| 213 | MAKEFLAGS= cov-build --config "$cov_config/config.xml" \\ |
| 214 | --dir "$cov_dir/golden" $@ |
| 215 | else |
| 216 | echo " golden: cov-build skipped" >&3 |
| 217 | fi |
| 218 | EOF |
| 219 | |
| 220 | |
| 221 | # cov-analyze on golden; only performed if a comparison file doesn't |
| 222 | # exist. |
| 223 | cat <<EOF | name="golden-cov-analyze" deps="golden-cov-build" \ |
| 224 | create_snippet |
| 225 | if [ ! -f "$golden_snapshot" -o -n "$cov_force_commit" ]; then |
| 226 | cd -P "$golden_repo" |
| 227 | cov-analyze --dir "$cov_dir/golden" $cov_options --verbose 0 \\ |
| 228 | --strip-path "\$(pwd -P)" \\ |
| 229 | --redirect "stdout,$cov_dir/golden.txt" |
| 230 | else |
| 231 | echo " golden: cov-analyze skipped" >&3 |
| 232 | fi |
| 233 | EOF |
| 234 | |
| 235 | |
| 236 | # cov-commit-defects on golden. Since more than one job could have |
| 237 | # started analyzing golden after finding the snapshot misssing, we check |
| 238 | # for a snapshot again, and a commit only performed if a comparison file |
| 239 | # doesn't exist. |
| 240 | cat <<EOF | name="golden-cov-commit-defects" \ |
| 241 | deps="stream-setup golden-cov-analyze" create_snippet |
| 242 | if [ ! -f "$golden_snapshot" -a -z "$cov_force_commit" ]; then |
| 243 | "$ci_root/script/get_latest_snapshot.py" \\ |
| 244 | --host "$coverity_host" \\ |
Zelalem | 219df41 | 2020-05-17 19:21:20 -0500 | [diff] [blame] | 245 | --https-port "$coverity_port" \\ |
Fathi Boudra | 422bf77 | 2019-12-02 11:10:16 +0200 | [diff] [blame] | 246 | --file "$golden_snapshot" \\ |
| 247 | --description "*$cov_checker*" \\ |
| 248 | --version "\$(git show -q --format=%H)" \\ |
| 249 | "$stream_name" 2>&3 || true |
| 250 | retried=1 |
| 251 | fi |
| 252 | |
| 253 | if [ ! -f "$golden_snapshot" -o -n "$cov_force_commit" ]; then |
| 254 | cd -P "$golden_repo" |
| 255 | cov-commit-defects --dir "$cov_dir/golden" --host "$coverity_host" \\ |
Zelalem | 219df41 | 2020-05-17 19:21:20 -0500 | [diff] [blame] | 256 | --https-port "$coverity_port" \\ |
Fathi Boudra | 422bf77 | 2019-12-02 11:10:16 +0200 | [diff] [blame] | 257 | --stream "$stream_name" --auth-key-file "$auth_file" \\ |
| 258 | --version "\$(git show -q --format=%H)" \\ |
| 259 | --description "$description" \\ |
| 260 | --snapshot-id-file "$golden_snapshot" |
| 261 | echo " golden: new snapshot ID: \$(cat $golden_snapshot)" >&3 |
| 262 | elif [ "\$retried" ]; then |
| 263 | { |
| 264 | echo " golden: snapshot ID \$(cat $golden_snapshot) now exists" |
| 265 | echo " golden: cov-commit-defects skipped" |
| 266 | } >&3 |
| 267 | else |
| 268 | echo " golden: cov-commit-defects skipped" >&3 |
| 269 | fi |
| 270 | EOF |
| 271 | |
| 272 | |
| 273 | # cov-build on branch |
| 274 | cat <<EOF | name="branch-cov-build" deps="cov-config branch-setup" \ |
| 275 | create_snippet |
| 276 | cd -P "$branch_repo" |
| 277 | MAKEFLAGS= cov-build --config "$cov_config/config.xml" --dir "$cov_dir/branch" $@ |
| 278 | EOF |
| 279 | |
| 280 | |
| 281 | # cov-analyze on branch |
| 282 | cat <<EOF | name="branch-cov-analyze" deps="branch-cov-build" \ |
| 283 | create_snippet |
| 284 | cd -P "$branch_repo" |
| 285 | cov-analyze --dir "$cov_dir/branch" $cov_options --verbose 0 \\ |
| 286 | --strip-path "\$(pwd -P)" \\ |
| 287 | --redirect "stdout,$cov_dir/branch.txt" |
| 288 | EOF |
| 289 | |
| 290 | |
| 291 | # cov-commit-defects on branch |
| 292 | cat <<EOF | name="branch-cov-commit-defects" \ |
| 293 | deps="stream-setup branch-cov-analyze" create_snippet |
| 294 | if [ "$cov_force_commit" ]; then |
| 295 | cd -P "$branch_repo" |
| 296 | cov-commit-defects --dir "$cov_dir/branch" --host "$coverity_host" \\ |
Zelalem | 219df41 | 2020-05-17 19:21:20 -0500 | [diff] [blame] | 297 | --https-port "$coverity_port" \\ |
Fathi Boudra | 422bf77 | 2019-12-02 11:10:16 +0200 | [diff] [blame] | 298 | --stream "$stream_name" --description "$description" \\ |
| 299 | --version "\$(git show -q --format=%H%)" \\ |
| 300 | --auth-key-file "$auth_file" \\ |
| 301 | --snapshot-id-file "$branch_snapshot" |
| 302 | echo " branch: new snapshot ID: \$(cat $branch_snapshot)" >&3 |
| 303 | else |
| 304 | echo " branch: cov-commit-defects skipped" >&3 |
| 305 | fi |
| 306 | EOF |
| 307 | |
| 308 | |
| 309 | # cov-commit-defects on branch, but compare with golden |
| 310 | cat <<EOF | name="branch-report-compare" \ |
| 311 | deps="golden-cov-commit-defects branch-cov-analyze" create_snippet |
| 312 | cov-commit-defects --dir "$cov_dir/branch" --host "$coverity_host" \\ |
Zelalem | 219df41 | 2020-05-17 19:21:20 -0500 | [diff] [blame] | 313 | --https-port "$coverity_port" \\ |
Fathi Boudra | 422bf77 | 2019-12-02 11:10:16 +0200 | [diff] [blame] | 314 | --stream "$stream_name" --auth-key-file "$auth_file" \\ |
| 315 | --preview-report-v2 "$cov_dir/report.json" \\ |
| 316 | --comparison-snapshot-id "\$(cat $golden_snapshot)" |
| 317 | EOF |
| 318 | |
| 319 | |
| 320 | # cov-commit-defects on branch to report branch report |
| 321 | cat <<EOF | name="branch-report-full" \ |
| 322 | deps="branch-cov-commit-defects stream-setup branch-cov-analyze" \ |
| 323 | create_snippet |
| 324 | cov-commit-defects --dir "$cov_dir/branch" --host "$coverity_host" \\ |
Zelalem | 219df41 | 2020-05-17 19:21:20 -0500 | [diff] [blame] | 325 | --https-port "$coverity_port" \\ |
Fathi Boudra | 422bf77 | 2019-12-02 11:10:16 +0200 | [diff] [blame] | 326 | --stream "$stream_name" --auth-key-file "$auth_file" \\ |
| 327 | --preview-report-v2 "$cov_dir/report.json" |
| 328 | EOF |
| 329 | |
| 330 | local minus_j="-j" |
| 331 | if upon "$cov_serial_build"; then |
| 332 | minus_j= |
| 333 | fi |
| 334 | |
| 335 | # Call Coverity targets |
| 336 | echo "Coverity run type: ${cov_run_type:?}" |
| 337 | if ! eval MAKEFLAGS= make -r $minus_j -f "$makefile" $cov_run_type; then |
| 338 | return 1 |
| 339 | fi |
| 340 | |
| 341 | # Generate a text report |
| 342 | local defects_file="$workspace/coverity_report.txt" |
| 343 | |
| 344 | if [ -f "$cov_dir/report.json" ]; then |
| 345 | python3 "$ci_root/script/coverity_parser.py" \ |
| 346 | --output "$workspace/defects.json" \ |
| 347 | $cov_report_options \ |
| 348 | "$cov_dir/report.json" >"$defects_file" 2>&3 || true |
| 349 | fi |
| 350 | |
| 351 | # If there were defects, print them out to the console. For local CI, |
| 352 | # print them in yellow--the same color we'd use for UNSTABLE builds. |
| 353 | if [ -s "$defects_file" ]; then |
| 354 | echo_w |
| 355 | echo_w "Coverity defects found:" |
| 356 | echo_w |
| 357 | if upon "$local_ci"; then |
| 358 | echo_w "$(tput setaf 3)" |
| 359 | fi |
| 360 | cat "$defects_file" >&3 |
| 361 | if upon "$local_ci"; then |
| 362 | echo_w "$(tput sgr0)" |
| 363 | fi |
| 364 | echo_w |
| 365 | echo_w "$(wc -l < "$defects_file") defects reported." |
| 366 | echo_w |
| 367 | build_unstable >&3 |
| 368 | echo_w |
| 369 | else |
| 370 | echo_w |
| 371 | echo_w "No coverity defects found." |
| 372 | echo_w |
| 373 | fi |
| 374 | } |