| #!/usr/bin/env bash |
| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # SHELLDOC-IGNORE |
| |
| SPOTBUGS_HOME=${SPOTBUGS_HOME:-} |
| ANT_SPOTBUGSXML=${ANT_SPOTBUGSXML:-} |
| SPOTBUGS_WARNINGS_FAIL_PRECHECK=false |
| |
| add_test_type spotbugs |
| |
| function spotbugs_usage |
| { |
| yetus_add_option "--spotbugs-home=<dir>" "SpotBugs home directory (default \${SPOTBUGS_HOME})" |
| yetus_add_option "--spotbugs-strict-precheck" "If there are SpotBugs warnings during precheck, fail" |
| } |
| |
| function spotbugs_parse_args |
| { |
| declare i |
| |
| for i in "$@"; do |
| case ${i} in |
| --spotbugs-home=*) |
| delete_parameter "${i}" |
| SPOTBUGS_HOME=${i#*=} |
| ;; |
| --spotbugs-strict-precheck) |
| delete_parameter "${i}" |
| SPOTBUGS_WARNINGS_FAIL_PRECHECK=true |
| ;; |
| esac |
| done |
| } |
| |
| ## @description initialize the spotbugs plug-in |
| ## @audience private |
| ## @stability evolving |
| ## @replaceable no |
| function spotbugs_initialize |
| { |
| if declare -f maven_add_install >/dev/null 2>&1; then |
| maven_add_install "spotbugs" |
| fi |
| } |
| |
| function spotbugs_filefilter |
| { |
| declare filename=$1 |
| |
| if [[ ${BUILDTOOL} == maven |
| || ${BUILDTOOL} == ant ]]; then |
| if [[ ${filename} =~ \.java$ |
| || ${filename} =~ (^|/)spotbugs-exclude.xml$ ]]; then |
| add_test "spotbugs" |
| fi |
| fi |
| } |
| |
| function spotbugs_precheck |
| { |
| declare exec |
| declare status=0 |
| |
| if [[ -z ${SPOTBUGS_HOME} ]]; then |
| yetus_error "SPOTBUGS_HOME was not specified." |
| status=1 |
| else |
| for exec in computeBugHistory \ |
| convertXmlToText \ |
| filterBugs \ |
| setBugDatabaseInfo\ |
| unionBugs; do |
| if ! verify_command "${exec}" "${SPOTBUGS_HOME}/bin/${exec}"; then |
| status=1 |
| fi |
| done |
| fi |
| if [[ ${status} == 1 ]]; then |
| add_vote_table_v2 0 "spotbugs" "" "spotbugs executables are not available." |
| delete_test "spotbugs" |
| return 0 |
| fi |
| } |
| |
| ## @description Run the maven spotbugs plugin and record found issues in a bug database |
| ## @audience private |
| ## @stability evolving |
| ## @replaceable no |
| ## @return 0 on success |
| ## @return 1 on failure |
| ## @param repostatus |
| function spotbugs_runner |
| { |
| declare name=$1 |
| declare module |
| declare result=0 |
| declare fn |
| declare warnings_file |
| declare i=0 |
| declare savestop |
| declare retval |
| |
| |
| personality_modules_wrapper "${name}" "spotbugs" |
| |
| "${BUILDTOOL}_modules_worker" "${name}" "spotbugs" |
| |
| if [[ ${UNSUPPORTED_TEST} = true ]]; then |
| return 0 |
| fi |
| |
| echo "" |
| echo "Building spotbugs database(s) using ${SPOTBUGS_HOME} for executables." |
| echo "" |
| |
| #shellcheck disable=SC2153 |
| until [[ ${i} -eq ${#MODULE[@]} ]]; do |
| if [[ ${MODULE_STATUS[i]} == -1 ]]; then |
| ((result=result+1)) |
| ((i=i+1)) |
| continue |
| fi |
| start_clock |
| offset_clock "${MODULE_STATUS_TIMER[i]}" |
| module="${MODULE[i]}" |
| fn=$(module_file_fragment "${module}") |
| |
| if [[ "${module}" == . ]]; then |
| module=root |
| fi |
| |
| case ${BUILDTOOL} in |
| maven) |
| targetfile="spotbugsXml.xml" |
| ;; |
| ant) |
| targetfile="${ANT_SPOTBUGSXML}" |
| ;; |
| esac |
| |
| buildtool_cwd "${i}" |
| |
| files=() |
| while read -r line; do |
| files+=("${line}") |
| done < <(find . -name "${targetfile}") |
| |
| warnings_file="${PATCH_DIR}/${name}-spotbugs-${fn}-warnings" |
| |
| if [[ "${#files[@]}" -lt 1 ]]; then |
| module_status "${i}" 0 "" "${name}/${module} no spotbugs output file (${targetfile})" |
| ((i=i+1)) |
| popd >/dev/null || return 1 |
| continue |
| elif [[ "${#files[@]}" -eq 1 ]]; then |
| cp -p "${files[0]}" "${warnings_file}.xml" |
| else |
| "${SPOTBUGS_HOME}/bin/unionBugs" -withMessages -output "${warnings_file}.xml" "${files[@]}" |
| fi |
| |
| popd >/dev/null || return 1 |
| |
| if [[ ${name} == branch ]]; then |
| "${SPOTBUGS_HOME}/bin/setBugDatabaseInfo" -name "${PATCH_BRANCH}" \ |
| "${warnings_file}.xml" "${warnings_file}.xml" |
| retval=$? |
| else |
| "${SPOTBUGS_HOME}/bin/setBugDatabaseInfo" -name patch \ |
| "${warnings_file}.xml" "${warnings_file}.xml" |
| retval=$? |
| fi |
| |
| if [[ ${retval} != 0 ]]; then |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[i]=${savestop} |
| module_status "${i}" -1 "" "${name}/${module} cannot run setBugDatabaseInfo from spotbugs" |
| ((result=result+1)) |
| ((i=i+1)) |
| continue |
| fi |
| |
| if [[ ! -f "${warnings_file}.xml" ]]; then |
| module_status "${i}" 0 "" "${name}/${module} no data in SpotBugs output file (${targetfile})" |
| ((i=i+1)) |
| popd >/dev/null || return 1 |
| continue |
| fi |
| |
| if ! "${SPOTBUGS_HOME}/bin/convertXmlToText" -html \ |
| "${warnings_file}.xml" \ |
| "${warnings_file}.html"; then |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[i]=${savestop} |
| module_status "${i}" -1 "" "${name}/${module} cannot run convertXmlToText from spotbugs" |
| ((result=result+1)) |
| fi |
| |
| if [[ -z ${SPOTBUGS_VERSION} |
| && ${name} == branch ]]; then |
| SPOTBUGS_VERSION=$("${GREP}" -i "BugCollection version=" "${warnings_file}.xml" \ |
| | cut -f2 -d\" \ |
| | cut -f1 -d\" ) |
| if [[ -n ${SPOTBUGS_VERSION} ]]; then |
| add_version_data "spotbugs" "${SPOTBUGS_VERSION}" |
| fi |
| fi |
| |
| ((i=i+1)) |
| done |
| |
| return "${result}" |
| } |
| |
| ## @description Track pre-existing spotbugs warnings |
| ## @audience private |
| ## @stability evolving |
| ## @replaceable no |
| ## @return 0 on success |
| ## @return 1 on failure |
| function spotbugs_preapply |
| { |
| declare fn |
| declare module |
| declare modindex=0 |
| declare warnings_file |
| declare module_spotbugs_warnings |
| declare result=0 |
| declare msg |
| |
| if ! verify_needed_test "spotbugs"; then |
| return 0 |
| fi |
| |
| big_console_header "spotbugs detection: ${PATCH_BRANCH}" |
| |
| spotbugs_runner branch |
| result=$? |
| |
| if [[ ${UNSUPPORTED_TEST} = true ]]; then |
| return 0 |
| fi |
| |
| until [[ ${modindex} -eq ${#MODULE[@]} ]]; do |
| if [[ ${MODULE_STATUS[modindex]} == -1 ]]; then |
| ((result=result+1)) |
| ((modindex=modindex+1)) |
| continue |
| fi |
| |
| module=${MODULE[modindex]} |
| start_clock |
| offset_clock "${MODULE_STATUS_TIMER[modindex]}" |
| fn=$(module_file_fragment "${module}") |
| |
| if [[ "${module}" == . ]]; then |
| module=root |
| fi |
| |
| warnings_file="${PATCH_DIR}/branch-spotbugs-${fn}-warnings" |
| if [[ ! -f "${warnings_file}.xml" ]]; then |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[modindex]=${savestop} |
| ((modindex=modindex+1)) |
| continue |
| fi |
| |
| # shellcheck disable=SC2016 |
| module_spotbugs_warnings=$("${SPOTBUGS_HOME}/bin/filterBugs" -first \ |
| "${PATCH_BRANCH}" \ |
| "${warnings_file}.xml" \ |
| "${warnings_file}.xml" \ |
| | "${AWK}" '{print $1}') |
| |
| if [[ ${module_spotbugs_warnings} -gt 0 ]] ; then |
| msg="${module} in ${PATCH_BRANCH} has ${module_spotbugs_warnings} extant spotbugs warnings." |
| if [[ "${SPOTBUGS_WARNINGS_FAIL_PRECHECK}" = "true" ]]; then |
| module_status "${modindex}" -1 "branch-spotbugs-${fn}-warnings.html" "${msg}" |
| ((result=result+1)) |
| elif [[ "${BUILDMODE}" = full ]]; then |
| module_status "${modindex}" -1 "branch-spotbugs-${fn}-warnings.html" "${msg}" |
| ((result=result+1)) |
| populate_test_table "spotbugs" "module:${module}" |
| #shellcheck disable=SC2162 |
| while read line; do |
| firstpart=$(echo "${line}" | cut -f2 -d:) |
| secondpart=$(echo "${line}" | cut -f9- -d' ') |
| add_test_table "" "${firstpart}:${secondpart}" |
| done < <("${SPOTBUGS_HOME}/bin/convertXmlToText" "${warnings_file}.xml") |
| else |
| module_status "${modindex}" 0 "branch-spotbugs-${fn}-warnings.html" "${msg}" |
| fi |
| fi |
| |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[modindex]=${savestop} |
| ((modindex=modindex+1)) |
| done |
| modules_messages branch "spotbugs" true |
| |
| if [[ ${result} != 0 ]]; then |
| return 1 |
| fi |
| return 0 |
| } |
| |
| ## @description Verify patch does not trigger any spotbugs warnings |
| ## @audience private |
| ## @stability evolving |
| ## @replaceable no |
| ## @return 0 on success |
| ## @return 1 on failure |
| function spotbugs_postinstall |
| { |
| declare module |
| declare fn |
| declare combined_xml |
| declare branchxml |
| declare patchxml |
| declare newbugsbase |
| declare fixedbugsbase |
| declare branch_warnings |
| declare patch_warnings |
| declare fixed_warnings |
| declare line |
| declare firstpart |
| declare secondpart |
| declare i=0 |
| declare result=0 |
| declare savestop |
| declare summarize=true |
| declare statstring |
| |
| if ! verify_needed_test "spotbugs"; then |
| return 0 |
| fi |
| |
| big_console_header "spotbugs detection: ${BUILDMODE}" |
| |
| spotbugs_runner patch |
| |
| if [[ ${UNSUPPORTED_TEST} = true ]]; then |
| return 0 |
| fi |
| |
| until [[ $i -eq ${#MODULE[@]} ]]; do |
| if [[ ${MODULE_STATUS[i]} == -1 ]]; then |
| ((result=result+1)) |
| ((i=i+1)) |
| continue |
| fi |
| |
| start_clock |
| offset_clock "${MODULE_STATUS_TIMER[i]}" |
| module="${MODULE[i]}" |
| |
| buildtool_cwd "${i}" |
| |
| fn=$(module_file_fragment "${module}") |
| |
| if [[ "${module}" == . ]]; then |
| module=root |
| fi |
| |
| combined_xml="${PATCH_DIR}/combined-spotbugs-${fn}.xml" |
| branchxml="${PATCH_DIR}/branch-spotbugs-${fn}-warnings.xml" |
| patchxml="${PATCH_DIR}/patch-spotbugs-${fn}-warnings.xml" |
| |
| if [[ -f "${branchxml}" ]]; then |
| # shellcheck disable=SC2016 |
| branch_warnings=$("${SPOTBUGS_HOME}/bin/filterBugs" -first \ |
| "${PATCH_BRANCH}" \ |
| "${branchxml}" \ |
| "${branchxml}" \ |
| | ${AWK} '{print $1}') |
| else |
| branchxml=${patchxml} |
| fi |
| |
| newbugsbase="${PATCH_DIR}/new-spotbugs-${fn}" |
| fixedbugsbase="${PATCH_DIR}/fixed-spotbugs-${fn}" |
| |
| if [[ ! -f "${branchxml}" ]] && [[ ! -f "${patchxml}" ]]; then |
| module_status "${i}" 0 "" "${module} has no data from spotbugs" |
| ((result=result+1)) |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[i]=${savestop} |
| ((i=i+1)) |
| popd >/dev/null || return 1 |
| continue |
| fi |
| |
| echo "" |
| |
| if ! "${SPOTBUGS_HOME}/bin/computeBugHistory" -useAnalysisTimes -withMessages \ |
| -output "${combined_xml}" \ |
| "${branchxml}" \ |
| "${patchxml}"; then |
| module_status "${i}" -1 "" "${module} cannot run computeBugHistory from spotbugs" |
| ((result=result+1)) |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[i]=${savestop} |
| ((i=i+1)) |
| popd >/dev/null || return 1 |
| continue |
| fi |
| |
| # shellcheck disable=SC2016 |
| patch_warnings=$("${SPOTBUGS_HOME}/bin/filterBugs" -first \ |
| "patch" \ |
| "${patchxml}" \ |
| "${patchxml}" \ |
| | ${AWK} '{print $1}') |
| |
| #shellcheck disable=SC2016 |
| add_warnings=$("${SPOTBUGS_HOME}/bin/filterBugs" -first patch \ |
| "${combined_xml}" "${newbugsbase}.xml" | ${AWK} '{print $1}') |
| retval=$? |
| if [[ ${retval} != 0 ]]; then |
| module_status "${i}" -1 "" "${module} cannot run filterBugs (#1) from spotbugs" |
| ((result=result+1)) |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[i]=${savestop} |
| ((i=i+1)) |
| popd >/dev/null || return 1 |
| continue |
| fi |
| |
| #shellcheck disable=SC2016 |
| fixed_warnings=$("${SPOTBUGS_HOME}/bin/filterBugs" -fixed patch \ |
| "${combined_xml}" "${fixedbugsbase}.xml" | ${AWK} '{print $1}') |
| retval=$? |
| if [[ ${retval} != 0 ]]; then |
| module_status "${i}" -1 "" "${module} cannot run filterBugs (#2) from spotbugs" |
| ((result=result+1)) |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[i]=${savestop} |
| ((i=i+1)) |
| popd >/dev/null || return 1 |
| continue |
| fi |
| |
| statstring=$(generic_calcdiff_status "${branch_warnings}" "${patch_warnings}" "${add_warnings}") |
| |
| if ! "${SPOTBUGS_HOME}/bin/convertXmlToText" -html "${newbugsbase}.xml" \ |
| "${newbugsbase}.html"; then |
| module_status "${i}" -1 "" "${module} cannot run convertXmlToText from spotbugs" |
| ((result=result+1)) |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[i]=${savestop} |
| ((i=i+1)) |
| popd >/dev/null || return 1 |
| continue |
| fi |
| |
| if [[ ${add_warnings} -gt 0 ]] ; then |
| populate_test_table SpotBugs "module:${module}" |
| #shellcheck disable=SC2162 |
| while read line; do |
| firstpart=$(echo "${line}" | cut -f2 -d:) |
| secondpart=$(echo "${line}" | cut -f9- -d' ') |
| add_test_table "" "${firstpart}:${secondpart}" |
| done < <("${SPOTBUGS_HOME}/bin/convertXmlToText" "${newbugsbase}.xml") |
| |
| module_status "${i}" -1 "new-spotbugs-${fn}.html" "${module} ${statstring}" |
| ((result=result+1)) |
| elif [[ ${fixed_warnings} -gt 0 ]]; then |
| module_status "${i}" +1 "" "${module} ${statstring}" |
| summarize=false |
| fi |
| savestop=$(stop_clock) |
| MODULE_STATUS_TIMER[i]=${savestop} |
| popd >/dev/null || return 1 |
| ((i=i+1)) |
| done |
| |
| modules_messages patch spotbugs "${summarize}" |
| if [[ ${result} != 0 ]]; then |
| return 1 |
| fi |
| return 0 |
| } |
| |
| function spotbugs_rebuild |
| { |
| declare repostatus=$1 |
| |
| if [[ "${repostatus}" = branch || "${BUILDMODE}" = full ]]; then |
| spotbugs_preapply |
| else |
| spotbugs_postinstall |
| fi |
| } |