#!/bin/bash set -ef -o pipefail scripts=$(dirname $0) # shellcheck source=jenkins-helpers.sh . $scripts/jenkins-helpers.sh # Relative artifacts are used for generation of manifests and reproduction # instructions. rel_artifacts=artifacts artifacts=$(pwd)/$rel_artifacts fresh_dir $artifacts "$artifacts/manifests/*" "$artifacts/jenkins/*" # Process bisect-only args convert_args_to_variables "$@" shift "$SHIFT_CONVERTED_ARGS" obligatory_variables bad_url bad_branch build_script current_project declare bad_url bad_branch build_script current_project BUILD_URL="${BUILD_URL:-$(pwd)}" replay_log="${replay_log-}" reproduce_bisect="${reproduce_bisect:-false}" # Process build args and record them in build-parameters.sh convert_args_to_variables ^^ $reproduce_bisect %% $artifacts/manifests/build-parameters.sh "$@" $reproduce_bisect || manifest_pop obligatory_variables rr[ci_project] rr[ci_config] declare -A rr verbose="${verbose-true}" set -u if $verbose; then set -x; fi mkdir -p $artifacts/jenkins touch $artifacts/jenkins/build-name # shellcheck disable=SC2064 trap "eval \"echo ERROR at \${FUNCNAME[0]}:\${BASH_LINENO[0]}\" > $artifacts/failures" EXIT rebase_workaround=false rebase_workaround_opts=() case "${rr[ci_project]}/${rr[ci_config]}:$current_project" in tcwg_kernel/*-next-*:linux) # Workaround linux-next/master rebasing on top of linux-next/stable. # Search for regressions against linux-mainline:master (aka linux-next:stable). clone_or_update_repo $current_project stable $bad_url # Just in case linux-next:stable has advanced between the build and bisect jobs, # use merge base between linux-next:stable and $bad_branch. bad_rev="${bad_rev-$(git_rev_parse_long $current_project $bad_branch)}" linux_next_stable="${linux_next_stable-$(git -C $current_project merge-base HEAD $bad_rev)}" cat < $artifacts/test.sh < $artifacts/trigger-build-rebase < $artifacts/trigger-build-rebase <> $artifacts/trigger-build-rebase < $artifacts/trigger-build-reset < $artifacts/trigger-build-reset < $artifacts/trigger-build-retry < $artifacts/jenkins/mail-recipients.txt trap "" EXIT exit 0 elif [ x"$res" = x"125" ]; then # We have confirmed a regression, but not what we have been triggered # to bisect. echo "WARNING: build for bad_rev $bad_rev showed uninteresting regression" sed -i -e "s/\$/-uninteresting/" $artifacts/jenkins/build-name trap "" EXIT exit 0 fi if ! git bisect log | grep -q "^git bisect .* $bad_rev\$"; then git bisect bad $bad_rev ln -f -s "build-$bad_rev" "$artifacts/build-bad" ln -f -s "build-$bad_rev.sh" "$artifacts/manifests/build-bad.sh" fi # Clone interesting-commits.git repo, which contains a list of SHA1s # that might cut down bisection time. Mostly, these are first_bad and # last_good commits. interesting_commits_rev=${interesting_commits_rev-linaro-local/ci/${rr[ci_project]}} clone_or_update_repo ../interesting-commits $interesting_commits_rev https://git-us.linaro.org/toolchain/ci/interesting-commits.git auto $interesting_commits_rev interesting_commits_rev=$(git -C ../interesting-commits rev-parse HEAD) cat <> ../interesting-commits/$current_project fi if [ x"$kind" = x"regression" ]; then mapfile -t configs < <(grep "^$sha1" ../interesting-commits/$current_project | sed -e "s/^$sha1 *//") configs+=("${rr[ci_project]}"/"${rr[ci_config]}") mapfile -t configs < <(echo "${configs[@]}" | tr ' ' '\n' | sort -u) sed -i -e "s#^$sha1.*\$#$sha1 ${configs[*]}#" ../interesting-commits/$current_project fi git -C ../interesting-commits add . if [ x"$(git -C ../interesting-commits status --short)" = x"" ]; then # No file has changed. We've been here before... # E.g., this is a re-occuring regression in linux-next. exit 125 fi git -C ../interesting-commits commit -m "Add $kind $sha1 from $BUILD_URL ${configs[*]}" & local res=0 && wait $! || res=$? if [ x"$res" = x"0" ]; then git_init_linaro_local_remote ../interesting-commits baseline false git_push ../interesting-commits baseline linaro-local/ci/${rr[ci_project]} fi ) & wait $! || push_interesting_commit_result=$? } # Print first_bad revision (if detected) get_first_bad () { ( # Allow pipefail to handle error exit codes from git bisect log and grep. # Note that child shell inherits settings from parent shell, so we need # excplicitly set "+o pipefail". set -euf +o pipefail git bisect log | tail -n1 | grep "^# first bad commit:" \ | sed -e "s/^# first bad commit: \[\([0-9a-f]*\)\].*/\1/" ) } print_tested_revs () { ( # Allow pipefail to handle error exit codes from git bisect log and grep. # Note that child shell inherits settings from parent shell, so we need # excplicitly set "+o pipefail". set -euf +o pipefail local kind="$1" git bisect log | grep "^git bisect $1 " | sed -e "s/^git bisect $1 //" ) } # Try to reduce bisection range by testing regressions (and their parents) # identified in other configurations. touch ../interesting-commits/$current_project # This loop can generate lots of console noise. set +x while [ x"$(get_first_bad $artifacts/first-bad else # It seems $last_good was on a path that tested good, even though # it itself is bad. # # We need to be careful to avoid re-trigger loops assert_with_msg "Last good is not an ancestor of bad rev!" \ git merge-base --is-ancestor $last_good $bad_rev if git merge-base --is-ancestor $baseline_rev $last_good; then # $last_good is a child of $baseline_rev, so we can re-trigger # bisection with reduced bisection range. cat > $artifacts/trigger-bisect < $artifacts/jenkins/mail-recipients.txt trap "" EXIT exit 0 fi # This case will be handled similar to "git bisect run" failure below. # We are going to reset baseline to $first_bad. fi else # When "git bisect run" fails, e.g., due to merge-base of $baseline_rev and # $bad_rev is worse than $baseline_rev, we want to reset baseline to HEAD, # so that we catch most of the commits that introduced change in the result # metric. first_bad=$(git rev-parse HEAD) push_interesting_commit $first_bad "bad-merge-base" fi cd .. # Save BISECT_* logs find "$current_project" -path "$current_project/.git/BISECT_*" -print0 | xargs -0 -I@ mv @ $artifacts/git-logs/ # Remove any fail-safe email body rm -f $artifacts/jenkins/mail-body.txt if [ -f $artifacts/first-bad ]; then mkdir -p $artifacts/jenkins sed -i -e "s/\$/-$first_bad/" $artifacts/jenkins/build-name ln -f -s "build-$first_bad" "$artifacts/build-first_bad" ln -f -s "build-$first_bad.sh" "$artifacts/manifests/build-first_bad.sh" good_name="last_good" good_sha1="$last_good" bad_name="first_bad" bad_sha1="$first_bad" ln -f -s "build-$last_good" "$artifacts/build-last_good" ln -f -s "build-$last_good.sh" "$artifacts/manifests/build-last_good.sh" occurences="$(cat interesting-commits/$current_project | grep "^$first_bad" | sed -e "s/^$first_bad *//" | tr ' ' '\n' | sed "s#^# - #")" if [ "$(echo "$occurences" | wc -l)" -le 1 ]; then git_log_level="medium" else git_log_level="short" fi cat >> $artifacts/jenkins/mail-body.txt < $(git -C $current_project log --pretty=$git_log_level -n 1 $first_bad) EOF else good_name="baseline_rev" good_sha1="$baseline_rev" bad_name="bad" bad_sha1="$bad_rev" cat >> $artifacts/jenkins/mail-body.txt < $artifacts/jenkins/jira-body.txt <> $artifacts/jenkins/mail-body.txt <> $artifacts/jenkins/mail-body.txt <> $artifacts/jenkins/mail-body.txt <> $artifacts/jenkins/mail-body.txt <> $artifacts/jenkins/mail-body.txt < $artifacts/jenkins/mail-recipients.txt <> $artifacts/trigger-build-1-reset # Trigger master build now instead of waiting for next timed SCM trigger. if [ -f $artifacts/build-$bad_rev/trigger-build-$current_project ]; then cp $artifacts/build-$bad_rev/trigger-build-$current_project $artifacts/trigger-build-2-default else # When replaying a bisect we often skip the $bad_rev build, so we won't # have its artifacts. Use $first_bad's trigger-build-* instead. cp $artifacts/build-$first_bad/trigger-build-$current_project $artifacts/trigger-build-2-default sed -i -e "s/$first_bad/$bad_rev/" $artifacts/trigger-build-2-default fi trap "" EXIT