blob: e43bab40a90131158edd1ce3f86833e6864d0415 [file] [log] [blame]
#!/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
SPOTBUGS_TABLE_DUPE=false
if [[ -z "${SPOTBUGS_HOME}" && -n "${FINDBUGS_HOME}" ]]; then
SPOTBUGS_MODE=findbugs
else
SPOTBUGS_MODE=spotbugs
fi
add_test_type spotbugs
function spotbugs_deprecate_test_type
{
if [[ "${SPOTBUGS_MODE}" == spotbugs ]]; then
if replace_test_type spotbugs findbugs; then
yetus_error "WARNING: Found both spotbugs and findbugs. Disabling findbugs."
SPOTBUGS_TABLE_DUPE=true
fi
else
if replace_test_type findbugs spotbugs; then
yetus_error "WARNING: spotbugs has deprecated findbugs, but only found findbugs."
fi
fi
}
function spotbugs_usage
{
yetus_add_option "--spotbugs-home=<path>" "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=*)
SPOTBUGS_HOME=${i#*=}
;;
--spotbugs-strict-precheck)
SPOTBUGS_WARNINGS_FAIL_PRECHECK=true
;;
esac
done
}
## @description initialize the spotbugs plug-in
## @audience private
## @stability evolving
## @replaceable no
function spotbugs_initialize
{
if [[ "${SPOTBUGS_MODE}" == findbugs ]]; then
FINDBUGS_HOME=${SPOTBUGS_HOME:-${FINDBUGS_HOME}}
fi
if declare -f maven_add_install >/dev/null 2>&1; then
maven_add_install "${SPOTBUGS_MODE}"
fi
}
function spotbugs_filefilter
{
declare filename=$1
if [[ ${BUILDTOOL} == maven
|| ${BUILDTOOL} == ant ]]; then
if [[ ${filename} =~ \.java$
|| ${filename} =~ (^|/)${SPOTBUGS_MODE}-exclude.xml$ ]]; then
add_test "${SPOTBUGS_MODE}"
fi
fi
}
function spotbugs_precheck
{
declare exec
declare status=0
if [[ -z ${SPOTBUGS_HOME} ]]; then
yetus_error "SPOTBUGS_HOME (or FINDBUGS_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 0 "${SPOTBUGS_MODE}" "${SPOTBUGS_MODE} executables are not available."
delete_test "${SPOTBUGS_MODE}"
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 "${name}" "${SPOTBUGS_MODE}"
"${BUILDTOOL}_modules_worker" "${name}" "${SPOTBUGS_MODE}"
if [[ ${UNSUPPORTED_TEST} = true ]]; then
return 0
fi
echo ""
echo "Building ${SPOTBUGS_MODE} database(s) using ${SPOTBUGS_HOME} for executables."
echo ""
if [[ "${SPOTBUGS_TABLE_DUPE}" == true ]] && [[ "${name}" == branch ]]; then
add_vote_table 0 spotbugs "Both FindBugs and SpotBugs are enabled, using SpotBugs."
fi
#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="${SPOTBUGS_MODE}Xml.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_MODE}-${fn}-warnings"
if [[ "${#files[@]}" -lt 1 ]]; then
module_status ${i} 0 "" "${name}/${module} no ${SPOTBUGS_MODE} 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_MODE}"
((result=result+1))
((i=i+1))
continue
fi
if [[ ! -f "${warnings_file}.xml" ]]; then
module_status ${i} 0 "" "${name}/${module} no data in SpotBugs/FindBugs 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_MODE}"
((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_MODE}" "${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_MODE}"; then
return 0
fi
big_console_header "${SPOTBUGS_MODE} detection: ${PATCH_BRANCH}"
spotbugs_runner branch
result=$?
if [[ ${UNSUPPORTED_TEST} = true ]]; then
return 0
fi
if [[ "${SPOTBUGS_MODE}" == findbugs ]]; then
add_vote_table 0 spotbugs "Used deprecated FindBugs config; considering switching to SpotBugs."
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_MODE}-${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_MODE} warnings."
if [[ "${SPOTBUGS_WARNINGS_FAIL_PRECHECK}" = "true" ]]; then
module_status ${modindex} -1 "branch-${SPOTBUGS_MODE}-${fn}-warnings.html" "${msg}"
((result=result+1))
elif [[ "${BUILDMODE}" = full ]]; then
module_status ${modindex} -1 "branch-${SPOTBUGS_MODE}-${fn}-warnings.html" "${msg}"
((result=result+1))
populate_test_table "${SPOTBUGS_MODE}" "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_MODE}-${fn}-warnings.html" "${msg}"
fi
fi
savestop=$(stop_clock)
MODULE_STATUS_TIMER[${modindex}]=${savestop}
((modindex=modindex+1))
done
modules_messages branch "${SPOTBUGS_MODE}" 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_MODE}"; then
return 0
fi
big_console_header "${SPOTBUGS_MODE} 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_MODE}-${fn}.xml"
branchxml="${PATCH_DIR}/branch-${SPOTBUGS_MODE}-${fn}-warnings.xml"
patchxml="${PATCH_DIR}/patch-${SPOTBUGS_MODE}-${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_MODE}-${fn}"
fixedbugsbase="${PATCH_DIR}/fixed-${SPOTBUGS_MODE}-${fn}"
if [[ ! -f "${branchxml}" ]] && [[ ! -f "${patchxml}" ]]; then
module_status ${i} 0 "" "${module} has no data from ${SPOTBUGS_MODE}"
((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_MODE}"
((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_MODE}"
((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_MODE}"
((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_MODE}"
((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 FindBugs "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_MODE}-${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_MODE} "${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
}
##
## To be removed: FindBugs instead of SpotBugs
##
add_test_type findbugs
function findbugs_usage
{
yetus_add_option "--findbugs-home=<path>" "Findbugs home directory (default \${FINDBUGS_HOME})"
yetus_add_option "--findbugs-strict-precheck" "If there are Findbugs warnings during precheck, fail"
}
function findbugs_parse_args
{
declare i
for i in "$@"; do
case ${i} in
--findbugs-home=*)
SPOTBUGS_HOME=${i#*=}
;;
--findbugs-strict-precheck)
SPOTBUGS_WARNINGS_FAIL_PRECHECK=true
;;
esac
done
}
function findbugs_initialize
{
SPOTBUGS_MODE="findbugs"
ANT_SPOTBUGSXML=${ANT_FINDBUGSXML}
SPOTBUGS_HOME=${FINDBUGS_HOME}
spotbugs_initialize "$@"
}
function findbugs_filefilter
{
spotbugs_initialize "$@"
}
function findbugs_rebuild
{
spotbugs_rebuild "$@"
}