#!/bin/bash set -ef -o pipefail scripts=$(dirname $0) # shellcheck source=jenkins-helpers.sh . $scripts/jenkins-helpers.sh declare -A rr # Process bisect-only args convert_args_to_variables "$@" shift "$SHIFT_CONVERTED_ARGS" obligatory_variables bad_git build_script current_project declare bad_git build_script current_project # Relative artifacts are used for generation of manifests and reproduction # instructions. rel_artifacts="${rel_artifacts-artifacts}" artifacts=$(pwd)/$rel_artifacts fresh_dir $artifacts \ "$artifacts/manifest.sh" \ "$artifacts/build-parameters/manifest.sh" \ "$artifacts/jenkins/*" 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 %%build_parameters $artifacts/build-parameters "$@" $reproduce_bisect || manifest_pop obligatory_variables build_parameters rr[ci_project] rr[ci_config] declare build_parameters verbose="${verbose-true}" set -u if $verbose; then set -x; fi mkdir -p $artifacts/jenkins touch $artifacts/jenkins/build-name trap print_traceback EXIT bad_url="${bad_git%#*}" bad_branch="${bad_git#*#}" 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_git. 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 < "$xfail" fi ( echo echo "# From $BUILD_URL:" cat "$fails" | sed -e "s/^\([A-Z]\+: \)/flaky \| \1/" ) >> "$xfail" git -C gcc-compare-results add "$xfail_short" git -C gcc-compare-results commit -m "From $BUILD_URL" git -C gcc-compare-results review -s git -C gcc-compare-results pull --rebase gerrit refs/heads/master git -C gcc-compare-results push gerrit HEAD:refs/heads/master ) & res=0 && wait $! || res=$? # Ignore any failures in the above. ;; esac mkdir -p ./bisect # Save baseline build state, which we restore before individual bisect tests. # This ensures that "bad" bisect tests won't affect "good" ones and vice versa. baseline_exclude=( --exclude /bisect/ --exclude "/$rel_artifacts/" --exclude "/$current_project/" ) rsync -a --del --delete-excluded "${baseline_exclude[@]}" ./ ./bisect/baseline/ mkdir $artifacts/git-logs # Make sure the sources are clean before bisecting git -C $current_project reset -q --hard if [ -f "$replay_log" ]; then cp "$replay_log" $artifacts/git-logs/bisect_replay.sh git -C $current_project bisect replay $artifacts/git-logs/bisect_replay.sh else git -C $current_project bisect start fi # Hard-link BISECT_LOG inside $artifacts to guarantee its upload to jenkins. ln -f "$(pwd)"/$current_project/.git/BISECT_LOG $artifacts/git-logs/bisect_log if ! git -C $current_project bisect log \ | grep -q "^git bisect .* $baseline_rev\$"; then git -C $current_project bisect good $baseline_rev fi # Bisect script. # # With this script we find the first commit that has regressed compared # to baseline, but not, necessarily, the commit that caused regression in # $bad_rev. Consider the scenario: # - rev_10 produced good result "2000" -- this is current baseline # - rev_20 completely broke the build (say, result "10") # - rev_22 fixed the build # - rev_30 regressed the build to result "1000" -- this is the regression we # detected vs "2000" baseline. # # The script will identify rev_20 as the first failing commit, which will # cause the baseline to be reset to rev_20 with metric "10". When we then # rebuild master (at rev_30) we will see a /progression/ from "10" to "1000", # thus missing the regression of "2000" to "1000". # # To catch the "2000" to "1000" regression someone would need to manually # trigger bisect between rev_22 and rev_30. # # We reduce the impact of the above by assigning negative values to result # metric for builds that look very broken, and do not bisect regressions into # the "negative" side. cat > $artifacts/test.sh <> $artifacts/trigger-build-rebase < $artifacts/trigger-build-reset < $commits_to_test # Bisecting linux-next.git regressions is difficult enough due to how # the tree is constructed, so we prefer to not use interesting-commits # when $rebase_workaround is true. This makes linux-next bisects as # natural as they can be. if $rebase_workaround; then return 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. local icommits="bisect/interesting-commits" clone_or_update_repo $icommits master \ https://git-us.linaro.org/toolchain/ci/interesting-commits.git \ auto master >/dev/null 2>&1 local project_dir project_dir=$icommits/$(interesting_subdir $current_project) if ! [ -d "$project_dir" ]; then return fi # Below loop can generate lots of console noise. set +x # Find an interesting commit that splits bisection range best. local sha1 prev_sha1 best_split=-1 best_sha1="" while read sha1; do while read prev_sha1; do split=$(print_sha1_split "$prev_sha1") if [ $split -gt $best_split ]; then best_split=$split best_sha1=$prev_sha1 fi done < <(echo "$sha1" cd "$project_dir/$sha1" find -name last_good -print0 | xargs -0 cat | sort -u) done < <(cd "$project_dir"; ls) echo "$best_split $best_sha1" ) } commits_to_test=$artifacts/git-logs/commits_to_test IFS=" " read -r split sha1 <<< "$(print_interesting_commit)" # Record commits in the initial bisect range. These are commits_to_test plus # commits that have been tested. commits_in_range=$artifacts/git-logs/commits_in_range cp $commits_to_test $commits_in_range print_tested_revs >> $commits_in_range while [ x"$sha1" != x"" ] \ && [ x"$(get_first_bad $artifacts/trigger-build-1-last-good <> $artifacts/trigger-build-2-reset fi # Trigger master build now instead of waiting for next timed SCM trigger. cp $artifacts/build-$bad_rev/trigger-build-$current_project \ $artifacts/trigger-build-3-default # Save BISECT_* logs find "$current_project" -path "$current_project/.git/BISECT_*" -print0 \ | xargs -0 -I@ mv @ $artifacts/git-logs/ if [ x"$first_bad" != x"" ]; then sed -i -e "s/\$/-$first_bad/" $artifacts/jenkins/build-name ln -f -s "build-$first_bad" "$artifacts/build-first_bad" ln -f -s "build-$last_good" "$artifacts/build-last_good" fi trap "" EXIT