yetus-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bus...@apache.org
Subject [04/10] yetus git commit: YETUS-6 Reoganize repository for split to TLP.
Date Wed, 28 Oct 2015 04:31:39 GMT
http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/author.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/author.sh b/precommit/test-patch.d/author.sh
new file mode 100755
index 0000000..d456bbb
--- /dev/null
+++ b/precommit/test-patch.d/author.sh
@@ -0,0 +1,52 @@
+#!/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.
+
+add_test_type author
+
+## @description  Check the current directory for @author tags
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function author_patchfile
+{
+  declare patchfile=$1
+  declare authorTags
+  # shellcheck disable=SC2155
+  declare -r appname=$(basename "${BASH_SOURCE-$0}")
+
+  big_console_header "Checking there are no @author tags in the patch."
+
+  start_clock
+
+  if [[ ${CHANGED_FILES} =~ ${appname} ]]; then
+    echo "Skipping @author checks as ${appname} has been patched."
+    add_vote_table 0 @author "Skipping @author checks as ${appname} has been patched."
+    return 0
+  fi
+
+  authorTags=$("${GREP}" -c -i '^[^-].*@author' "${patchfile}")
+  echo "There appear to be ${authorTags} @author tags in the patch."
+  if [[ ${authorTags} != 0 ]] ; then
+    add_vote_table -1 @author \
+      "The patch appears to contain ${authorTags} @author tags which the" \
+      " community has agreed to not allow in code contributions."
+    return 1
+  fi
+  add_vote_table +1 @author "The patch does not contain any @author tags."
+  return 0
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/cc.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/cc.sh b/precommit/test-patch.d/cc.sh
new file mode 100755
index 0000000..cae91d3
--- /dev/null
+++ b/precommit/test-patch.d/cc.sh
@@ -0,0 +1,63 @@
+#!/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.
+
+add_test_type cc
+
+function cc_filefilter
+{
+  declare filename=$1
+
+  if [[ ${filename} =~ \.c$
+      || ${filename} =~ \.cc$
+      || ${filename} =~ \.cpp$
+      || ${filename} =~ \.cxx$
+      || ${filename} =~ \.h$
+      || ${filename} =~ \.hh$
+     ]]; then
+   yetus_debug "tests/cc: ${filename}"
+   add_test cc
+   add_test compile
+  fi
+}
+
+## @description  check for C/C++ compiler errors
+## @audience     private
+## @stability    stable
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function cc_compile
+{
+  declare codebase=$1
+  declare multijdkmode=$2
+
+  verify_needed_test cc
+  if [[ $? = 0 ]]; then
+    return 0
+  fi
+
+  if [[ ${codebase} = patch ]]; then
+    generic_postlog_compare compile cc "${multijdkmode}"
+  fi
+}
+
+function cc_count_probs
+{
+  declare warningfile=$1
+
+  #shellcheck disable=SC2016,SC2046
+  ${GREP} -E '^.*\.(c|cc|h|hh)\:[[:digit:]]*\:' "${warningfile}" | ${AWK} '{sum+=1} END {print sum}'
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/checkstyle.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/checkstyle.sh b/precommit/test-patch.d/checkstyle.sh
new file mode 100755
index 0000000..24b9ffc
--- /dev/null
+++ b/precommit/test-patch.d/checkstyle.sh
@@ -0,0 +1,237 @@
+#!/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.
+
+add_test_type checkstyle
+
+CHECKSTYLE_TIMER=0
+
+function checkstyle_filefilter
+{
+  local filename=$1
+
+  if [[ ${BUILDTOOL} == maven
+    || ${BUILDTOOL} == ant ]]; then
+    if [[ ${filename} =~ \.java$ ]]; then
+      add_test checkstyle
+    fi
+  fi
+}
+
+function checkstyle_runner
+{
+  local repostatus=$1
+  local tmp=${PATCH_DIR}/$$.${RANDOM}
+  local j
+  local i=0
+  local fn
+  local savestart=${TIMER}
+  local savestop
+  local output
+  local logfile
+  local repo
+  local modulesuffix
+  local cmd
+
+  modules_reset
+
+  if [[ ${repostatus} == branch ]]; then
+    repo=${PATCH_BRANCH}
+  else
+    repo="the patch"
+  fi
+
+  #shellcheck disable=SC2153
+  until [[ $i -eq ${#MODULE[@]} ]]; do
+    start_clock
+    fn=$(module_file_fragment "${MODULE[${i}]}")
+    modulesuffix=$(basename "${MODULE[${i}]}")
+    output="${PATCH_DIR}/${repostatus}-checkstyle-${fn}.txt"
+    logfile="${PATCH_DIR}/maven-${repostatus}-checkstyle-${fn}.txt"
+
+    if [[ ${BUILDTOOLCWD} == true ]]; then
+      pushd "${BASEDIR}/${MODULE[${i}]}" >/dev/null
+    fi
+
+    case ${BUILDTOOL} in
+      ant)
+        cmd="${ANT}  \
+          -Dcheckstyle.consoleOutput=true \
+          ${MODULEEXTRAPARAM[${i}]//@@@MODULEFN@@@/${fn}} \
+          ${ANT_ARGS[*]} checkstyle"
+      ;;
+      maven)
+        cmd="${MAVEN} ${MAVEN_ARGS[*]} \
+           checkstyle:checkstyle \
+          -Dcheckstyle.consoleOutput=true \
+          ${MODULEEXTRAPARAM[${i}]//@@@MODULEFN@@@/${fn}} -Ptest-patch"
+      ;;
+      *)
+        UNSUPPORTED_TEST=true
+        return 0
+      ;;
+    esac
+
+    #shellcheck disable=SC2086
+    echo ${cmd} "> ${logfile}"
+    #shellcheck disable=SC2086
+    ${cmd}  2>&1 \
+            | tee "${logfile}" \
+            | ${GREP} ^/ \
+            | ${SED} -e "s,${BASEDIR},.,g" \
+                > "${tmp}"
+
+    if [[ $? == 0 ]] ; then
+      module_status ${i} +1 "${logfile}" "${modulesuffix} in ${repo} passed checkstyle"
+    else
+      module_status ${i} -1 "${logfile}" "${modulesuffix} in ${repo} failed checkstyle"
+      ((result = result + 1))
+    fi
+    savestop=$(stop_clock)
+    #shellcheck disable=SC2034
+    MODULE_STATUS_TIMER[${i}]=${savestop}
+
+    for j in ${CHANGED_FILES}; do
+      ${GREP} "${j}" "${tmp}" >> "${output}"
+    done
+
+    rm "${tmp}" 2>/dev/null
+
+    if [[ ${BUILDTOOLCWD} == true ]]; then
+      popd >/dev/null
+    fi
+    ((i=i+1))
+  done
+
+  TIMER=${savestart}
+
+  if [[ ${result} -gt 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+function checkstyle_postcompile
+{
+  declare repostatus=$1
+
+  if [[ "${repostatus}" = branch ]]; then
+    checkstyle_preapply
+  else
+    checkstyle_postapply
+  fi
+}
+
+function checkstyle_preapply
+{
+  local result
+
+  verify_needed_test checkstyle
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+
+  big_console_header "${PATCH_BRANCH} checkstyle"
+
+  start_clock
+
+  personality_modules branch checkstyle
+  checkstyle_runner branch
+  result=$?
+  modules_messages branch checkstyle true
+
+  # keep track of how much as elapsed for us already
+  CHECKSTYLE_TIMER=$(stop_clock)
+  if [[ ${result} != 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+function checkstyle_postapply
+{
+  local result
+  local module
+  local mod
+  local fn
+  local i=0
+  local numprepatch=0
+  local numpostpatch=0
+  local diffpostpatch=0
+
+  verify_needed_test checkstyle
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+
+  big_console_header "Patch checkstyle plugin"
+
+  start_clock
+
+  personality_modules patch checkstyle
+  checkstyle_runner patch
+  result=$?
+
+  if [[ ${UNSUPPORTED_TEST} = true ]]; then
+    return 0
+  fi
+
+  # add our previous elapsed to our new timer
+  # by setting the clock back
+  offset_clock "${CHECKSTYLE_TIMER}"
+
+  until [[ $i -eq ${#MODULE[@]} ]]; do
+    if [[ ${MODULE_STATUS[${i}]} == -1 ]]; then
+      ((result=result+1))
+      ((i=i+1))
+      continue
+    fi
+    module=${MODULE[$i]}
+    fn=$(module_file_fragment "${module}")
+
+    if [[ ! -f "${PATCH_DIR}/branch-checkstyle-${fn}.txt" ]]; then
+      touch "${PATCH_DIR}/branch-checkstyle-${fn}.txt"
+    fi
+
+    calcdiffs "${PATCH_DIR}/branch-checkstyle-${fn}.txt" "${PATCH_DIR}/patch-checkstyle-${fn}.txt" > "${PATCH_DIR}/diff-checkstyle-${fn}.txt"
+    #shellcheck disable=SC2016
+    diffpostpatch=$(wc -l "${PATCH_DIR}/diff-checkstyle-${fn}.txt" | ${AWK} '{print $1}')
+
+    if [[ ${diffpostpatch} -gt 0 ]] ; then
+      ((result = result + 1))
+
+      # shellcheck disable=SC2016
+      numprepatch=$(wc -l "${PATCH_DIR}/branch-checkstyle-${fn}.txt" | ${AWK} '{print $1}')
+      # shellcheck disable=SC2016
+      numpostpatch=$(wc -l "${PATCH_DIR}/patch-checkstyle-${fn}.txt" | ${AWK} '{print $1}')
+
+      mod=${module}
+      if [[ ${mod} == . ]]; then
+        mod=root
+      fi
+      module_status ${i} -1 "diff-checkstyle-${fn}.txt" "Patch generated "\
+        "${diffpostpatch} new checkstyle issues in "\
+        "${mod} (total was ${numprepatch}, now ${numpostpatch})."
+    fi
+    ((i=i+1))
+  done
+
+  modules_messages patch checkstyle true
+
+  if [[ ${result} != 0 ]]; then
+    return 1
+  fi
+  return 0
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/findbugs.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/findbugs.sh b/precommit/test-patch.d/findbugs.sh
new file mode 100755
index 0000000..ae18893
--- /dev/null
+++ b/precommit/test-patch.d/findbugs.sh
@@ -0,0 +1,411 @@
+#!/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.
+
+
+FINDBUGS_HOME=${FINDBUGS_HOME:-}
+FINDBUGS_WARNINGS_FAIL_PRECHECK=false
+
+add_test_type findbugs
+
+function findbugs_filefilter
+{
+  local filename=$1
+
+  if [[ ${BUILDTOOL} == maven
+    || ${BUILDTOOL} == ant ]]; then
+    if [[ ${filename} =~ \.java$
+      || ${filename} =~ (^|/)findbugs-exclude.xml$ ]]; then
+      add_test findbugs
+    fi
+  fi
+}
+
+function findbugs_usage
+{
+  echo "FindBugs specific:"
+  echo "--findbugs-home=<path> Findbugs home directory (default FINDBUGS_HOME environment variable)"
+  echo "--findbugs-strict-precheck If there are Findbugs warnings during precheck, fail"
+}
+
+function findbugs_parse_args
+{
+  local i
+
+  for i in "$@"; do
+    case ${i} in
+    --findbugs-home=*)
+      FINDBUGS_HOME=${i#*=}
+    ;;
+    --findbugs-strict-precheck)
+      FINDBUGS_WARNINGS_FAIL_PRECHECK=true
+    ;;
+    esac
+  done
+}
+
+## @description  are the needed bits for findbugs present?
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 findbugs will work for our use
+## @return       1 findbugs is missing some component
+function findbugs_is_installed
+{
+  declare exec
+  declare status=0
+
+  for exec in findbugs \
+              computeBugHistory \
+              convertXmlToText \
+              filterBugs \
+              setBugDatabaseInfo; do
+    if [[ ! -x "${FINDBUGS_HOME}/bin/${exec}"  ]]; then
+      yetus_error "ERROR: ${FINDBUGS_HOME}/bin/${exec} is not executable."
+      status=1
+    fi
+  done
+  return ${status}
+}
+
+## @description  Run the maven findbugs plugin and record found issues in a bug database
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function findbugs_runner
+{
+  local name=$1
+  local module
+  local result=0
+  local fn
+  local warnings_file
+  local i=0
+  local savestop
+
+  personality_modules "${name}" findbugs
+  "${BUILDTOOL}_modules_worker" "${name}" findbugs
+
+  if [[ ${UNSUPPORTED_TEST} = true ]]; then
+    return 0
+  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}")
+
+    case ${BUILDTOOL} in
+      maven)
+        file="${module}/target/findbugsXml.xml"
+      ;;
+      ant)
+        file="${ANT_FINDBUGSXML}"
+      ;;
+    esac
+
+
+    if [[ ! -f ${file} ]]; then
+      module_status ${i} -1 "" "${name}/${module} no findbugs output file (${file})"
+      ((i=i+1))
+      continue
+    fi
+
+    warnings_file="${PATCH_DIR}/${name}-findbugs-${fn}-warnings"
+
+    cp -p "${file}" "${warnings_file}.xml"
+
+    if [[ ${name} == branch ]]; then
+      "${FINDBUGS_HOME}/bin/setBugDatabaseInfo" -name "${PATCH_BRANCH}" \
+          "${warnings_file}.xml" "${warnings_file}.xml"
+    else
+      "${FINDBUGS_HOME}/bin/setBugDatabaseInfo" -name patch \
+          "${warnings_file}.xml" "${warnings_file}.xml"
+    fi
+    if [[ $? != 0 ]]; then
+      savestop=$(stop_clock)
+      MODULE_STATUS_TIMER[${i}]=${savestop}
+      module_status ${i} -1 "" "${name}/${module} cannot run setBugDatabaseInfo from findbugs"
+      ((result=result+1))
+      ((i=i+1))
+      continue
+    fi
+
+    "${FINDBUGS_HOME}/bin/convertXmlToText" -html \
+      "${warnings_file}.xml" \
+      "${warnings_file}.html"
+    if [[ $? != 0 ]]; then
+      savestop=$(stop_clock)
+      MODULE_STATUS_TIMER[${i}]=${savestop}
+      module_status ${i} -1 "" "${name}/${module} cannot run convertXmlToText from findbugs"
+      ((result=result+1))
+    fi
+
+    if [[ -z ${FINDBUGS_VERSION}
+        && ${name} == branch ]]; then
+      FINDBUGS_VERSION=$(${GREP} -i "BugCollection version=" "${warnings_file}.xml" \
+        | cut -f2 -d\" \
+        | cut -f1 -d\" )
+      if [[ -n ${FINDBUGS_VERSION} ]]; then
+        add_footer_table findbugs "v${FINDBUGS_VERSION}"
+      fi
+    fi
+
+    ((i=i+1))
+  done
+  return ${result}
+}
+
+## @description  Track pre-existing findbugs warnings
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function findbugs_preapply
+{
+  local fn
+  local module
+  local i=0
+  local warnings_file
+  local module_findbugs_warnings
+  local result=0
+
+  verify_needed_test findbugs
+
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+
+  findbugs_is_installed
+  if [[ $? != 0 ]]; then
+    add_vote_table 0 findbugs "findbugs executables are not available."
+    return 0
+  fi
+
+  big_console_header "Pre-patch findbugs detection"
+
+  findbugs_runner branch
+  result=$?
+
+  if [[ ${UNSUPPORTED_TEST} = true ]]; then
+    return 0
+  fi
+
+  if [[ "${FINDBUGS_WARNINGS_FAIL_PRECHECK}" == "true" ]]; then
+    until [[ $i -eq ${#MODULE[@]} ]]; do
+      if [[ ${MODULE_STATUS[${i}]} == -1 ]]; then
+        ((result=result+1))
+        ((i=i+1))
+        continue
+      fi
+      module=${MODULE[${i}]}
+      start_clock
+      offset_clock "${MODULE_STATUS_TIMER[${i}]}"
+      fn=$(module_file_fragment "${module}")
+      warnings_file="${PATCH_DIR}/branch-findbugs-${fn}-warnings"
+      # shellcheck disable=SC2016
+      module_findbugs_warnings=$("${FINDBUGS_HOME}/bin/filterBugs" -first \
+          "${PATCH_BRANCH}" \
+          "${warnings_file}.xml" \
+          "${warnings_file}.xml" \
+          | ${AWK} '{print $1}')
+
+      if [[ ${module_findbugs_warnings} -gt 0 ]] ; then
+        module_status ${i} -1 "branch-findbugs-${fn}.html" "${module} in ${PATCH_BRANCH} cannot run convertXmlToText from findbugs"
+        ((result=result+1))
+      fi
+      savestop=$(stop_clock)
+      MODULE_STATUS_TIMER[${i}]=${savestop}
+      ((i=i+1))
+    done
+    modules_messages branch findbugs true
+  fi
+
+  if [[ ${result} != 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+## @description  Verify patch does not trigger any findbugs warnings
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function findbugs_postinstall
+{
+  local module
+  local fn
+  local combined_xml
+  local branchxml
+  local patchxml
+  local newbugsbase
+  local fixedbugsbase
+  local new_findbugs_warnings
+  local fixed_findbugs_warnings
+  local line
+  local firstpart
+  local secondpart
+  local i=0
+  local result=0
+  local savestop
+
+  verify_needed_test findbugs
+
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+
+  findbugs_is_installed
+  if [[ $? != 0 ]]; then
+    return 0
+  fi
+
+  big_console_header "Patch findbugs detection"
+
+  findbugs_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}]}"
+
+    if [[ ${BUILDTOOLCWD} == true ]]; then
+      pushd "${module}" >/dev/null
+    fi
+
+    fn=$(module_file_fragment "${module}")
+
+    combined_xml="${PATCH_DIR}/combined-findbugs-${fn}.xml"
+    branchxml="${PATCH_DIR}/branch-findbugs-${fn}-warnings.xml"
+    patchxml="${PATCH_DIR}/patch-findbugs-${fn}-warnings.xml"
+
+    if [[ ! -f "${branchxml}" ]]; then
+      branchxml=${patchxml}
+    fi
+
+    newbugsbase="${PATCH_DIR}/new-findbugs-${fn}"
+    fixedbugsbase="${PATCH_DIR}/fixed-findbugs-${fn}"
+
+    "${FINDBUGS_HOME}/bin/computeBugHistory" -useAnalysisTimes -withMessages \
+            -output "${combined_xml}" \
+            "${branchxml}" \
+            "${patchxml}"
+    if [[ $? != 0 ]]; then
+      if [[ ${BUILDTOOLCWD} == true ]]; then
+        popd >/dev/null
+      fi
+      module_status ${i} -1 "" "${module} cannot run computeBugHistory from findbugs"
+      ((result=result+1))
+      savestop=$(stop_clock)
+      MODULE_STATUS_TIMER[${i}]=${savestop}
+      ((i=i+1))
+      continue
+    fi
+
+    #shellcheck disable=SC2016
+    new_findbugs_warnings=$("${FINDBUGS_HOME}/bin/filterBugs" -first patch \
+        "${combined_xml}" "${newbugsbase}.xml" | ${AWK} '{print $1}')
+    if [[ $? != 0 ]]; then
+      popd >/dev/null
+      module_status ${i} -1 "" "${module} cannot run filterBugs (#1) from findbugs"
+      ((result=result+1))
+      savestop=$(stop_clock)
+      MODULE_STATUS_TIMER[${i}]=${savestop}
+      ((i=i+1))
+      continue
+    fi
+
+    #shellcheck disable=SC2016
+    fixed_findbugs_warnings=$("${FINDBUGS_HOME}/bin/filterBugs" -fixed patch \
+        "${combined_xml}" "${fixedbugsbase}.xml" | ${AWK} '{print $1}')
+    if [[ $? != 0 ]]; then
+      popd >/dev/null
+      module_status ${i} -1 "" "${module} cannot run filterBugs (#2) from findbugs"
+      ((result=result+1))
+      savestop=$(stop_clock)
+      MODULE_STATUS_TIMER[${i}]=${savestop}
+      ((i=i+1))
+      continue
+    fi
+
+    echo "Found ${new_findbugs_warnings} new Findbugs warnings and ${fixed_findbugs_warnings} newly fixed warnings."
+
+    "${FINDBUGS_HOME}/bin/convertXmlToText" -html "${newbugsbase}.xml" \
+        "${newbugsbase}.html"
+    if [[ $? != 0 ]]; then
+      popd >/dev/null
+      module_status ${i} -1 "" "${module} cannot run convertXmlToText from findbugs"
+      ((result=result+1))
+      savestop=$(stop_clock)
+      MODULE_STATUS_TIMER[${i}]=${savestop}
+      ((i=i+1))
+      continue
+    fi
+
+    if [[ ${new_findbugs_warnings} -gt 0 ]] ; then
+      populate_test_table FindBugs "module:${module}"
+      while read line; do
+        firstpart=$(echo "${line}" | cut -f2 -d:)
+        secondpart=$(echo "${line}" | cut -f9- -d' ')
+        add_test_table "" "${firstpart}:${secondpart}"
+      done < <("${FINDBUGS_HOME}/bin/convertXmlToText" "${newbugsbase}.xml")
+
+      module_status ${i} -1 "new-findbugs-${fn}.html" "${module} introduced "\
+        "${new_findbugs_warnings} new FindBugs issues."
+      ((result=result+1))
+    fi
+    savestop=$(stop_clock)
+    MODULE_STATUS_TIMER[${i}]=${savestop}
+    popd >/dev/null
+    ((i=i+1))
+  done
+
+  modules_messages patch findbugs true
+  if [[ ${result} != 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+function findbugs_rebuild
+{
+  declare repostatus=$1
+
+  if [[ "${repostatus}" = branch ]]; then
+    findbugs_preapply
+  else
+    findbugs_postinstall
+  fi
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/github.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/github.sh b/precommit/test-patch.d/github.sh
new file mode 100755
index 0000000..468a228
--- /dev/null
+++ b/precommit/test-patch.d/github.sh
@@ -0,0 +1,492 @@
+#!/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.
+
+# This bug system provides github integration
+
+add_bugsystem github
+
+# personalities can override the following settings:
+
+# Web interface URL.
+GITHUB_BASE_URL="https://github.com"
+
+# API interface URL.
+GITHUB_API_URL="https://api.github.com"
+
+# user/repo
+GITHUB_REPO=""
+
+# user settings
+GITHUB_PASSWD=""
+GITHUB_TOKEN=""
+GITHUB_USER=""
+GITHUB_ISSUE=""
+
+# private globals...
+GITHUB_BRIDGED=false
+GITHUB_COMMITSHA=""
+
+function github_usage
+{
+  echo "GITHUB Options:"
+  echo "--github-api-url=<url>   The URL of the API for github (default: '${GITHUB_API_URL}')"
+  echo "--github-base-url=<url>  The URL of the github server (default:'${GITHUB_BASE_URL}')"
+  echo "--github-password=<pw>   Github password"
+  echo "--github-repo=<repo>     github repo to use (default:'${GITHUB_REPO}')"
+  echo "--github-token=<token>   The token to use to write to github"
+  echo "--github-user=<user>     Github user"
+}
+
+function github_parse_args
+{
+  declare i
+
+  for i in "$@"; do
+    case ${i} in
+      --github-api-url=*)
+        GITHUB_API_URL=${i#*=}
+      ;;
+      --github-base-url=*)
+        GITHUB_BASE_URL=${i#*=}
+      ;;
+      --github-repo=*)
+        GITHUB_REPO=${i#*=}
+      ;;
+      --github-token=*)
+        GITHUB_TOKEN=${i#*=}
+      ;;
+      --github-password=*)
+        GITHUB_PASSWD=${i#*=}
+      ;;
+      --github-user=*)
+        GITHUB_USER=${i#*=}
+      ;;
+    esac
+  done
+}
+
+## @description this gets called when JIRA thinks this
+## @description issue is just a pointer to github
+## @description WARNING: Called from JIRA plugin!
+function github_jira_bridge
+{
+  declare fileloc=$1
+  declare urlfromjira
+
+  # we use this to prevent loops later on
+  GITHUB_BRIDGED=true
+
+  # the JIRA issue has already been downloaded. So let's find the URL.
+  # shellcheck disable=SC2016
+  urlfromjira=$(${AWK} "match(\$0,\"${GITHUB_BASE_URL}/[^ ]*patch\"){print substr(\$0,RSTART,RLENGTH)}" "${PATCH_DIR}/jira" | tail -1)
+  github_breakup_url "${urlfromjira}"
+  github_locate_patch "${GITHUB_ISSUE}" "${fileloc}"
+}
+
+## @description given a URL, break it up into github plugin globals
+## @description this will *override* any personality or yetus defaults
+## @params url
+function github_breakup_url
+{
+  declare url=$1
+  declare count
+  declare pos1
+  declare pos2
+
+  count=${url//[^\/]}
+  count=${#count}
+  ((pos2=count-3))
+  ((pos1=pos2))
+
+  GITHUB_BASE_URL=$(echo "${url}" | cut -f1-${pos2} -d/)
+
+  ((pos1=pos1+1))
+  ((pos2=pos1+1))
+
+  GITHUB_REPO=$(echo "${url}" | cut -f${pos1}-${pos2} -d/)
+
+  ((pos1=pos2+2))
+  unset pos2
+
+  GITHUB_ISSUE=$(echo "${url}" | cut -f${pos1}-${pos2} -d/ | cut -f1 -d.)
+}
+
+
+## @description based upon a github PR, attempt to link back to JIRA
+function github_find_jira_title
+{
+  declare title
+  declare maybe
+  declare retval
+
+  if [[ ! -f "${PATCH_DIR}/github-pull.json" ]]; then
+    return 1
+  fi
+
+  title=$(${GREP} title "${PATCH_DIR}/github-pull.json" \
+    | cut -f4 -d\")
+
+  # people typically do two types:  JIRA-ISSUE: and [JIRA-ISSUE]
+  # JIRA_ISSUE_RE is pretty strict so we need to chop that stuff
+  # out first
+
+  maybe=$(echo "${title}" | cut -f2 -d\[ | cut -f1 -d\])
+  jira_determine_issue "${maybe}"
+  retval=$?
+
+  if [[ ${retval} == 0 ]]; then
+    return 0
+  fi
+
+  maybe=$(echo "${title}" | cut -f1 -d:)
+  jira_determine_issue "${maybe}"
+  retval=$?
+
+  if [[ ${retval} == 0 ]]; then
+    return 0
+  fi
+
+  return 1
+}
+
+function github_determine_issue
+{
+  declare input=$1
+
+  if [[ ${input} =~ ^[0-9]+$
+     && -n ${GITHUB_REPO} ]]; then
+    # shellcheck disable=SC2034
+    ISSUE=${input}
+    if [[ -z ${GITHUB_ISSUE} ]]; then
+      GITHUB_ISSUE=${input}
+    fi
+  fi
+
+  # if JIRA didn't call us, should we call it?
+  if [[ ${GITHUB_BRIDGED} == false ]]; then
+    github_find_jira_title
+    if [[ $? == 0 ]]; then
+      return 0
+    fi
+  fi
+
+  if [[ -n ${GITHUB_ISSUE} ]]; then
+    return 0
+  fi
+
+  return 1
+}
+
+## @description  Try to guess the branch being tested using a variety of heuristics
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success, with PATCH_BRANCH updated appropriately
+## @return       1 on failure
+function github_determine_branch
+{
+  if [[ ! -f "${PATCH_DIR}/github-pull.json" ]]; then
+    return 1
+  fi
+
+  # shellcheck disable=SC2016
+  PATCH_BRANCH=$(${AWK} 'match($0,"\"ref\": \""){print $2}' "${PATCH_DIR}/github-pull.json"\
+     | cut -f2 -d\"\
+     | tail -1  )
+
+  yetus_debug "Github determine branch: starting with ${PATCH_BRANCH}"
+
+  verify_valid_branch  "${PATCH_BRANCH}"
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+  return 1
+}
+
+function github_locate_patch
+{
+  declare input=$1
+  declare output=$2
+  declare githubauth
+
+  if [[ "${OFFLINE}" == true ]]; then
+    yetus_debug "github_locate_patch: offline, skipping"
+    return 1
+  fi
+
+
+  # https://github.com/your/repo/pull/##
+  if [[ ${input} =~ ^${GITHUB_BASE_URL}.*/pull/[0-9]+$ ]]; then
+    github_breakup_url "${input}.patch"
+    input=${GITHUB_ISSUE}
+  fi
+
+  # https://github.com/your/repo/pulls/##.patch
+  if [[ ${input} =~ ^${GITHUB_BASE_URL}.*patch$ ]]; then
+    github_breakup_url "${input}"
+    input=${GITHUB_ISSUE}
+  fi
+
+  # https://github.com/your/repo/pulls/##.diff
+  if [[ ${input} =~ ^${GITHUB_BASE_URL}.*diff$ ]]; then
+    github_breakup_url "${input}"
+    input=${GITHUB_ISSUE}
+  fi
+
+  # if it isn't a number at this point, no idea
+  # how to process
+  if [[ ! ${input} =~ ^[0-9]+$ ]]; then
+    yetus_debug "github: ${input} is not a pull request #"
+    return 1
+  fi
+
+  # we always pull the .patch version (even if .diff was given)
+  # with the assumption that this way binary files work.
+  # The downside of this is that the patch files are
+  # significantly larger and therefore take longer to process
+  PATCHURL="${GITHUB_BASE_URL}/${GITHUB_REPO}/pull/${input}.patch"
+  echo "GITHUB PR #${input} is being downloaded at $(date) from"
+  echo "${GITHUB_BASE_URL}/${GITHUB_REPO}/pull/${input}"
+
+  if [[ -n "${GITHUB_USER}"
+     && -n "${GITHUB_PASSWD}" ]]; then
+    githubauth="${GITHUB_USER}:${GITHUB_PASSWD}"
+  elif [[ -n "${GITHUB_TOKEN}" ]]; then
+    githubauth="Authorization: token ${GITHUB_TOKEN}"
+  else
+    githubauth="X-ignore-me: fake"
+  fi
+
+  # Let's pull the PR JSON for later use
+  ${CURL} --silent --fail \
+          -H "Accept: application/vnd.github.v3.full+json" \
+          -H "${githubauth}" \
+          --output "${PATCH_DIR}/github-pull.json" \
+          --location \
+         "${GITHUB_API_URL}/repos/${GITHUB_REPO}/pulls/${input}"
+
+  echo "Patch from GITHUB PR #${input} is being downloaded at $(date) from"
+  echo "${PATCHURL}"
+
+  # the actual patch file
+  ${CURL} --silent --fail \
+          --output "${output}" \
+          --location \
+          -H "${githubauth}" \
+         "${PATCHURL}"
+
+  if [[ $? != 0 ]]; then
+    yetus_debug "github_locate_patch: not a github pull request."
+    return 1
+  fi
+
+  GITHUB_ISSUE=${input}
+
+  # github will translate this to be #(xx) !
+  add_footer_table "GITHUB PR" "${GITHUB_BASE_URL}/${GITHUB_REPO}/pull/${input}"
+
+  return 0
+}
+
+function github_linecomments
+{
+  declare plugin=$1
+  declare file=$2
+  # shellcheck disable=SC2034
+  declare realline=$3
+  declare uniline=$4
+  declare text=$5
+  declare tempfile="${PATCH_DIR}/ghcomment.$$.${RANDOM}"
+  declare githubauth
+
+  if [[ "${file}" =~ ^./ ]]; then
+    file=${file##./}
+  fi
+
+  if [[ -z "${GITHUB_COMMITSHA}" ]]; then
+    GITHUB_COMMITSHA=$(${GREP} \"sha\" "${PATCH_DIR}/github-pull.json" 2>/dev/null \
+      | head -1 \
+      | cut -f4 -d\")
+  fi
+
+  if [[ -z "${uniline}" ]]; then
+    return
+  fi
+
+  # build our REST post
+  {
+    printf "{\"body\":\""
+    echo "${plugin}: ${text}" \
+      | ${SED} -e 's,\\,\\\\,g' \
+        -e 's,\",\\\",g' \
+        -e 's,$,\\r\\n,g' \
+      | tr -d '\n'
+    echo "\","
+    echo "\"commit_id\":\"${GITHUB_COMMITSHA}\","
+    echo "\"path\":\"${file}\","
+    echo "\"position\":${uniline}"
+    echo "}"
+  } > "${tempfile}"
+
+  if [[ -n "${GITHUB_USER}"
+     && -n "${GITHUB_PASSWD}" ]]; then
+    githubauth="${GITHUB_USER}:${GITHUB_PASSWD}"
+  elif [[ -n "${GITHUB_TOKEN}" ]]; then
+    githubauth="Authorization: token ${GITHUB_TOKEN}"
+  else
+    return 0
+  fi
+
+  ${CURL} -X POST \
+    -H "Accept: application/vnd.github.v3.full+json" \
+    -H "Content-Type: application/json" \
+    -H "${githubauth}" \
+    -d @"${tempfile}" \
+    --silent --location \
+    "${GITHUB_API_URL}/repos/${GITHUB_REPO}/pulls/${GITHUB_ISSUE}/comments" \
+    >/dev/null
+  rm "${tempfile}"
+}
+
+## @description Write the contents of a file to github
+## @params filename
+## @stability stable
+## @audience public
+function github_write_comment
+{
+  declare -r commentfile=${1}
+  declare retval=0
+  declare restfile="${PATCH_DIR}/ghcomment.$$"
+  declare githubauth
+
+  if [[ "${OFFLINE}" == true ]]; then
+    echo "Github Plugin: Running in offline, comment skipped."
+    return 0
+  fi
+
+  {
+    printf "{\"body\":\""
+    ${SED} -e 's,\\,\\\\,g' \
+        -e 's,\",\\\",g' \
+        -e 's,$,\\r\\n,g' "${commentfile}" \
+    | tr -d '\n'
+    echo "\"}"
+  } > "${restfile}"
+
+  if [[ -n "${GITHUB_USER}"
+     && -n "${GITHUB_PASSWD}" ]]; then
+    githubauth="${GITHUB_USER}:${GITHUB_PASSWD}"
+  elif [[ -n "${GITHUB_TOKEN}" ]]; then
+    githubauth="Authorization: token ${GITHUB_TOKEN}"
+  else
+    echo "Github Plugin: no credentials provided to write a comment."
+    return 0
+  fi
+
+  ${CURL} -X POST \
+       -H "Accept: application/vnd.github.v3.full+json" \
+       -H "Content-Type: application/json" \
+       -H "${githubauth}" \
+       -d @"${restfile}" \
+       --silent --location \
+         "${GITHUB_API_URL}/repos/${GITHUB_REPO}/issues/${GITHUB_ISSUE}/comments" \
+        >/dev/null
+
+  retval=$?
+  rm "${restfile}"
+  return ${retval}
+}
+
+## @description  Print out the finished details to the Github PR
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        runresult
+function github_finalreport
+{
+  declare result=$1
+  declare i
+  declare commentfile=${PATCH_DIR}/gitcommentfile.$$
+  declare comment
+
+  rm "${commentfile}" 2>/dev/null
+
+  if [[ ${JENKINS} != "true"
+    || -z ${GITHUB_ISSUE} ]] ; then
+    return 0
+  fi
+
+  big_console_header "Adding comment to Github"
+
+  add_footer_table "Console output" "${BUILD_URL}console"
+
+  if [[ ${result} == 0 ]]; then
+    echo ":confetti_ball: **+1 overall**" >> "${commentfile}"
+  else
+    echo ":broken_heart: **-1 overall**" >> "${commentfile}"
+  fi
+
+  printf "\n\n\n\n" >>  "${commentfile}"
+
+  i=0
+  until [[ ${i} -eq ${#TP_HEADER[@]} ]]; do
+    printf "%s\n\n" "${TP_HEADER[${i}]}" >> "${commentfile}"
+    ((i=i+1))
+  done
+
+  {
+    printf "\n\n"
+    echo "| Vote | Subsystem | Runtime | Comment |"
+    echo "|:----:|----------:|--------:|:--------|"
+  } >> "${commentfile}"
+
+  i=0
+  until [[ ${i} -eq ${#TP_VOTE_TABLE[@]} ]]; do
+    echo "${TP_VOTE_TABLE[${i}]}" >> "${commentfile}"
+    ((i=i+1))
+  done
+
+  if [[ ${#TP_TEST_TABLE[@]} -gt 0 ]]; then
+    {
+      printf "\n\n"
+      echo "| Reason | Tests |"
+      echo "|-------:|:------|"
+    } >> "${commentfile}"
+    i=0
+    until [[ ${i} -eq ${#TP_TEST_TABLE[@]} ]]; do
+      echo "${TP_TEST_TABLE[${i}]}" >> "${commentfile}"
+      ((i=i+1))
+    done
+  fi
+
+  {
+    printf "\n\n"
+    echo "| Subsystem | Report/Notes |"
+    echo "|----------:|:-------------|"
+  } >> "${commentfile}"
+
+  i=0
+  until [[ $i -eq ${#TP_FOOTER_TABLE[@]} ]]; do
+    comment=$(echo "${TP_FOOTER_TABLE[${i}]}" |
+              ${SED} -e "s,@@BASE@@,${BUILD_URL}artifact/patchprocess,g")
+    printf "%s\n" "${comment}" >> "${commentfile}"
+    ((i=i+1))
+  done
+
+  printf "\n\nThis message was automatically generated.\n\n" >> "${commentfile}"
+
+  github_write_comment "${commentfile}"
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/gradle.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/gradle.sh b/precommit/test-patch.d/gradle.sh
new file mode 100755
index 0000000..56da8d5
--- /dev/null
+++ b/precommit/test-patch.d/gradle.sh
@@ -0,0 +1,263 @@
+#!/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.
+
+add_build_tool gradle
+
+declare -a GRADLE_ARGS=()
+
+function gradle_usage
+{
+  echo "gradle specific:"
+  echo "--gradle-cmd=<cmd>        The 'gradle' command to use (default 'gradle')"
+  echo "--gradlew-cmd=<cmd>        The 'gradlew' command to use (default 'basedir/gradlew')"
+}
+
+function gradle_parse_args
+{
+  local i
+
+  for i in "$@"; do
+    case ${i} in
+      --gradle-cmd=*)
+        GRADLE=${i#*=}
+      ;;
+      --gradlew-cmd=*)
+        GRADLEW=${i#*=}
+      ;;
+    esac
+  done
+
+  # if we requested offline, pass that to mvn
+  if [[ ${OFFLINE} == "true" ]]; then
+    GRADLE_ARGS=("${GRADLE_ARGS[@]}" --offline)
+  fi
+
+  GRADLE=${GRADLE:-gradle}
+  GRADLEW=${GRADLEW:-"${BASEDIR}/gradlew"}
+}
+
+function gradle_initialize
+{
+  if [[ "${BUILDTOOL}" = gradle ]]; then
+    # shellcheck disable=SC2034
+    BUILDTOOLCWD=false
+  fi
+
+  # we need to do this before docker kicks in
+  if [[ -e "${HOME}/.gradle"
+     && ! -d "${HOME}/.gradle" ]]; then
+    yetus_error "ERROR: ${HOME}/.gradle is not a directory."
+    return 1
+  elif [[ ! -e "${HOME}/.gradle" ]]; then
+    yetus_debug "Creating ${HOME}/.gradle"
+    mkdir -p "${HOME}/.gradle"
+  fi
+}
+
+function gradle_buildfile
+{
+  echo "gradlew"
+}
+
+function gradle_executor
+{
+  echo "${GRADLEW}" "${GRADLE_ARGS[@]}"
+}
+
+## @description  Bootstrap gradle
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function gradle_precompile
+{
+  declare repostatus=$1
+  declare result=0
+
+  if [[ ${BUILDTOOL} != gradle ]]; then
+    return 0
+  fi
+
+  if [[ "${repostatus}" = branch ]]; then
+    # shellcheck disable=SC2153
+    big_console_header "${PATCH_BRANCH} gradle bootstrap"
+  else
+    big_console_header "Patch gradle bootstrap"
+  fi
+
+  personality_modules "${repostatus}" gradleboot
+
+  pushd "${BASEDIR}" >/dev/null
+  echo_and_redirect "${PATCH_DIR}/${repostatus}-gradle-bootstrap.txt" gradle -b bootstrap.gradle
+  popd >/dev/null
+
+  modules_workers "${repostatus}" gradleboot
+  result=$?
+  modules_messages "${repostatus}" gradleboot true
+  if [[ ${result} != 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+function gradle_scalac_count_probs
+{
+  local warningfile=$1
+
+  #shellcheck disable=SC2016,SC2046
+  ${GREP} "^/.*.scala:[0-9]*:" "${warningfile}" | wc -l
+}
+
+function gradle_javac_count_probs
+{
+  echo 0
+}
+
+function gradle_javadoc_count_probs
+{
+  echo 0
+}
+
+## @description  Helper for check_patch_javadoc
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function gradle_scaladoc_count_probs
+{
+  local warningfile=$1
+
+  #shellcheck disable=SC2016,SC2046
+  ${GREP} "^\[ant:scaladoc\]" "${warningfile}" | wc -l
+}
+
+function gradle_modules_worker
+{
+  declare repostatus=$1
+  declare tst=$2
+  shift 2
+
+  # shellcheck disable=SC2034
+  UNSUPPORTED_TEST=false
+
+  case ${tst} in
+    checkstyle)
+      modules_workers "${repostatus}" "${tst}" checkstyleMain checkstyleTest
+    ;;
+    compile)
+      modules_workers "${repostatus}" "${tst}"
+    ;;
+    distclean)
+      modules_workers "${repostatus}" clean
+    ;;
+    javadoc)
+      modules_workers "${repostatus}" "${tst}" javadoc
+    ;;
+    scaladoc)
+      modules_workers "${repostatus}" "${tst}" scaladoc
+    ;;
+    unit)
+      modules_workers "${repostatus}" "${tst}" test
+    ;;
+    *)
+      # shellcheck disable=SC2034
+      UNSUPPORTED_TEST=true
+      if [[ ${repostatus} = patch ]]; then
+        add_footer_table "${tst}" "not supported by the ${BUILDTOOL} plugin"
+      fi
+      yetus_error "WARNING: ${tst} is unsupported by ${BUILDTOOL}"
+      return 1
+    ;;
+  esac
+}
+
+function gradle_builtin_personality_modules
+{
+  local repostatus=$1
+  local testtype=$2
+
+  local module
+
+  yetus_debug "Using builtin personality_modules"
+  yetus_debug "Personality: ${repostatus} ${testtype}"
+
+  clear_personality_queue
+
+  for module in ${CHANGED_MODULES}; do
+    # shellcheck disable=SC2086
+    personality_enqueue_module ${module}
+  done
+}
+
+function gradle_builtin_personality_file_tests
+{
+  local filename=$1
+
+  yetus_debug "Using builtin gradle personality_file_tests"
+
+  if [[ ${filename} =~ src/main/webapp ]]; then
+    yetus_debug "tests/webapp: ${filename}"
+  elif [[ ${filename} =~ \.sh
+       || ${filename} =~ \.cmd
+       || ${filename} =~ src/main/scripts
+       || ${filename} =~ src/test/scripts
+       ]]; then
+    yetus_debug "tests/shell: ${filename}"
+  elif [[ ${filename} =~ \.c$
+       || ${filename} =~ \.cc$
+       || ${filename} =~ \.h$
+       || ${filename} =~ \.hh$
+       || ${filename} =~ \.proto$
+       || ${filename} =~ \.cmake$
+       || ${filename} =~ CMakeLists.txt
+       ]]; then
+    yetus_debug "tests/units: ${filename}"
+    add_test cc
+    add_test unit
+  elif [[ ${filename} =~ \.scala$ ]]; then
+    add_test scalac
+    add_test scaladoc
+    add_test unit
+  elif [[ ${filename} =~ build.xml$
+       || ${filename} =~ pom.xml$
+       || ${filename} =~ \.java$
+       ]]; then
+    yetus_debug "tests/javadoc+units: ${filename}"
+    add_test javac
+    add_test javadoc
+    add_test unit
+  elif [[ ${filename} =~ src/main ]]; then
+    yetus_debug "tests/generic+units: ${filename}"
+    add_test compile
+    add_test unit
+  fi
+
+  if [[ ${filename} =~ src/test ]]; then
+    yetus_debug "tests"
+    add_test unit
+  fi
+
+  if [[ ${filename} =~ \.java$ ]]; then
+    add_test findbugs
+  fi
+}
+
+function gradle_docker_support
+{
+  echo "-v ${HOME}/.gradle:${HOME}/.gradle" > "${PATCH_DIR}/buildtool-docker-params.txt"
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/java.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/java.sh b/precommit/test-patch.d/java.sh
new file mode 100755
index 0000000..e1a73c7
--- /dev/null
+++ b/precommit/test-patch.d/java.sh
@@ -0,0 +1,168 @@
+#!/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.
+
+add_test_type javac
+add_test_type javadoc
+
+function javac_initialize
+{
+  local i
+  local jdkdir
+  local tmplist
+
+  # if we are in pre-docker mode, don't do any of
+  # this work since it's all going to be wrong anyway
+  if [[ "${DOCKERSUPPORT}" = "true" ]]; then
+    return 0
+  fi
+
+  if [[ -z ${JAVA_HOME:-} ]]; then
+    case ${OSTYPE} in
+      Darwin)
+        if [[ -z "${JAVA_HOME}" ]]; then
+          if [[ -x /usr/libexec/java_home ]]; then
+            JAVA_HOME="$(/usr/libexec/java_home)"
+            export JAVA_HOME
+          else
+            export JAVA_HOME=/Library/Java/Home
+          fi
+        fi
+      ;;
+      *)
+        yetus_error "WARNING: JAVA_HOME not defined. Disabling java tests."
+        delete_test javac
+        delete_test javadoc
+        return 1
+      ;;
+    esac
+  fi
+
+  JAVA_HOME=$(cd -P -- "${JAVA_HOME}" >/dev/null && pwd -P)
+
+  for i in ${JDK_DIR_LIST}; do
+    if [[ -d "${i}" ]]; then
+      jdkdir=$(cd -P -- "${i}" >/dev/null && pwd -P)
+      if [[ ${jdkdir} != "${JAVA_HOME}" ]]; then
+        tmplist="${tmplist} ${jdkdir}"
+      fi
+    else
+      yetus_error "WARNING: Cannot locate JDK directory ${i}: ignoring"
+    fi
+  done
+
+  JDK_DIR_LIST="${tmplist} ${JAVA_HOME}"
+  JDK_DIR_LIST=${JDK_DIR_LIST/ }
+}
+
+## @description  Verify that ${JAVA_HOME} is defined
+## @audience     public
+## @stability    stable
+## @replaceable  no
+## @return       1 - no JAVA_HOME
+## @return       0 - JAVA_HOME defined
+function javac_precheck
+{
+  declare javaversion
+  declare listofjdks
+  declare i
+
+  start_clock
+
+  if [[ -z ${JAVA_HOME:-} ]]; then
+    yetus_error "ERROR: JAVA_HOME is not defined."
+    add_vote_table -1 pre-patch "JAVA_HOME is not defined."
+    return 1
+  fi
+
+  javaversion=$(report_jvm_version "${JAVA_HOME}")
+  add_footer_table "Default Java" "${javaversion}"
+
+  if [[ -n ${JDK_DIR_LIST}
+     && ${JDK_DIR_LIST} != "${JAVA_HOME}" ]]; then
+    for i in ${JDK_DIR_LIST}; do
+      javaversion=$(report_jvm_version "${i}")
+      listofjdks="${listofjdks} ${i}:${javaversion}"
+    done
+    add_footer_table "Multi-JDK versions" "${listofjdks}"
+  fi
+  return 0
+}
+
+function javac_filefilter
+{
+  declare filename=$1
+
+  if [[ ${filename} =~ \.java$ ]]; then
+   yetus_debug "tests/javac: ${filename}"
+   add_test javac
+   add_test compile
+  fi
+}
+
+function javadoc_filefilter
+{
+  local filename=$1
+
+  if [[ ${filename} =~ \.java$ ]]; then
+   yetus_debug "tests/javadoc: ${filename}"
+   add_test javadoc
+  fi
+}
+
+## @description
+## @audience     private
+## @stability    stable
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function javac_compile
+{
+  declare codebase=$1
+  declare multijdkmode=$2
+
+  verify_needed_test javac
+  if [[ $? = 0 ]]; then
+    return 0
+  fi
+
+  if [[ ${codebase} = patch ]]; then
+    yetus_debug "javac: calling generic_postlog_compare compile javac ${multijdkmode}"
+    generic_postlog_compare compile javac "${multijdkmode}"
+  fi
+}
+
+## @description  Count and compare the number of JavaDoc warnings pre- and post- patch
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function javadoc_rebuild
+{
+  declare codebase=$1
+  declare multijdkmode
+
+  verify_multijdk_test javadoc
+  if [[ $? == 1 ]]; then
+    multijdkmode=true
+  fi
+
+  if [[ "${codebase}" = branch ]]; then
+    generic_pre_handler javadoc "${multijdkmode}"
+  else
+    generic_post_handler javadoc javadoc "${multijdkmode}" true
+  fi
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/jira.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/jira.sh b/precommit/test-patch.d/jira.sh
new file mode 100755
index 0000000..e5fd550
--- /dev/null
+++ b/precommit/test-patch.d/jira.sh
@@ -0,0 +1,436 @@
+#!/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.
+
+# this bug system handles JIRA.  Personalities
+# can override the following variables:
+
+# base JIRA URL
+JIRA_URL=${JIRA_URL:-"https://issues.apache.org/jira"}
+
+# Issue regex to help identify the project
+JIRA_ISSUE_RE=''
+
+# If the issue status is matched with this pattern, the attached patch is regarded as ready to be applied
+JIRA_STATUS_RE='Patch Available'
+
+add_bugsystem jira
+
+function jira_usage
+{
+  echo "JIRA Options:"
+  echo "--jira-base-url=<url>   The URL of the JIRA server (default:'${JIRA_URL}')"
+  echo "--jira-issue-re=<expr>  Bash regular expression to use when trying to find a jira ref in the patch name (default: \'${JIRA_ISSUE_RE}\')"
+  echo "--jira-password=<pw>    The password for the 'jira' command"
+  echo "--jira-status-re=<expr> Grep regular expression representing the issue status whose patch is applicable to the codebase (default: \'${JIRA_STATUS_RE}\')"
+  echo "--jira-user=<user>      The user for the 'jira' command"
+}
+
+function jira_parse_args
+{
+  declare i
+
+  for i in "$@"; do
+    case ${i} in
+      --jira-base-url=*)
+        JIRA_URL=${i#*=}
+      ;;
+      --jira-issue-re=*)
+        JIRA_ISSUE_RE=${i#*=}
+      ;;
+      --jira-password=*)
+        JIRA_PASSWD=${i#*=}
+      ;;
+      --jira-status-re=*)
+        JIRA_STATUS_RE=${i#*=}
+      ;;
+      --jira-user=*)
+        JIRA_USER=${i#*=}
+      ;;
+    esac
+  done
+}
+
+## @description provides issue determination based upon the URL and more.
+## @description WARNING: called from the github plugin!
+function jira_determine_issue
+{
+  declare input=$1
+  declare patchnamechunk
+  declare maybeissue
+
+  if [[ -n ${JIRA_ISSUE} ]]; then
+    return 0
+  fi
+
+  # shellcheck disable=SC2016
+  patchnamechunk=$(echo "${input}" | ${AWK} -F/ '{print $NF}')
+
+  maybeissue=$(echo "${patchnamechunk}" | cut -f1,2 -d-)
+
+  if [[ ${maybeissue} =~ ${JIRA_ISSUE_RE} ]]; then
+    # shellcheck disable=SC2034
+    ISSUE=${maybeissue}
+    JIRA_ISSUE=${maybeissue}
+    add_footer_table "JIRA Issue" "${JIRA_ISSUE}"
+    return 0
+  fi
+
+  return 1
+}
+
+function jira_http_fetch
+{
+  declare input=$1
+  declare output=$2
+
+  if [[ -n "${JIRA_USER}"
+     && -n "${JIRA_PASSWD}" ]]; then
+    ${CURL} --silent --fail \
+            --user "${JIRA_USER}:${JIRA_PASSWD}" \
+            --output "${output}" \
+            --location \
+           "${JIRA_URL}/${input}"
+  else
+    ${CURL} --silent --fail \
+            --output "${output}" \
+            --location \
+           "${JIRA_URL}/${input}"
+  fi
+}
+
+function jira_locate_patch
+{
+  declare input=$1
+  declare fileloc=$2
+  declare relativeurl
+
+  yetus_debug "jira_locate_patch: trying ${JIRA_URL}/browse/${input}"
+
+  if [[ "${OFFLINE}" == true ]]; then
+    yetus_debug "jira_locate_patch: offline, skipping"
+    return 1
+  fi
+
+  jira_http_fetch "browse/${input}" "${PATCH_DIR}/jira"
+
+  if [[ $? != 0 ]]; then
+    yetus_debug "jira_locate_patch: not a JIRA."
+    return 1
+  fi
+
+  # if github is configured and we see what looks like a URL,
+  # send this to the github plugin to process.
+  if [[ -n "${GITHUB_BASE_URL}"
+      && $(${GREP} -c  "${GITHUB_BASE_URL}"'[^ ]*patch' "${PATCH_DIR}/jira") != 0 ]]; then
+    jira_determine_issue "${input}"
+    echo "${input} appears to be a Github PR. Switching Modes."
+    github_jira_bridge "${fileloc}"
+    return $?
+  elif [[ $(${GREP} -c "${JIRA_STATUS_RE}" "${PATCH_DIR}/jira") == 0 ]]; then
+    if [[ ${JENKINS} == true ]]; then
+      yetus_error "ERROR: ${input} issue status is not matched with \"${JIRA_STATUS_RE}\"."
+      cleanup_and_exit 1
+    else
+      yetus_error "WARNING: ${input} issue status is not matched with \"${JIRA_STATUS_RE}\"."
+    fi
+  fi
+
+  #shellcheck disable=SC2016
+  relativeurl=$(${AWK} 'match($0,"/secure/attachment/[0-9]*/[^\"]*"){print substr($0,RSTART,RLENGTH)}' "${PATCH_DIR}/jira" |
+    ${GREP} -v -e 'htm[l]*$' | sort | tail -1 | ${SED} -e 's,[ ]*$,,g')
+  PATCHURL="${JIRA_URL}${relativeurl}"
+  if [[ ! ${PATCHURL} =~ \.patch$ ]]; then
+    guess_patch_file "${PATCH_DIR}/patch"
+    if [[ $? == 0 ]]; then
+      yetus_debug "The patch ${PATCHURL} was not named properly, but it looks like a patch file. Proceeding, but issue/branch matching might go awry."
+      add_vote_table 0 patch "The patch file was not named according to ${PROJECT_NAME}'s naming conventions. Please see ${HOW_TO_CONTRIBUTE} for instructions."
+    fi
+  fi
+  echo "${input} patch is being downloaded at $(date) from"
+  echo "${PATCHURL}"
+  add_footer_table "JIRA Patch URL" "${PATCHURL}"
+  jira_http_fetch "${relativeurl}" "${fileloc}"
+  if [[ $? != 0 ]];then
+    yetus_error "ERROR: ${input}/${PATCHURL} could not be downloaded."
+    cleanup_and_exit 1
+  fi
+  return 0
+}
+
+## @description  Try to guess the branch being tested using a variety of heuristics
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success, with PATCH_BRANCH updated appropriately
+function jira_determine_branch
+{
+  declare patchnamechunk
+  declare total
+  declare count
+  declare hinttype
+
+  for hinttype in "${PATCHURL}" "${PATCH_OR_ISSUE}"; do
+    if [[ -z "${hinttype}" ]]; then
+      continue
+    fi
+
+    # If one of these matches the JIRA issue regex
+    # then we don't want it to trigger the branch
+    # detection since that's almost certainly not
+    # intended.  In other words, if ISSUE-99 is the
+    # name of a branch, you want to test ISSUE-99
+    # against master, not ISSUE-99's branch
+    if [[ ${hinttype} =~ ${JIRA_ISSUE_RE} ]]; then
+      continue
+    fi
+
+    yetus_debug "Determine branch: starting with ${hinttype}"
+    patchnamechunk=$(echo "${hinttype}" \
+            | ${SED} -e 's,.*/\(.*\)$,\1,' \
+                     -e 's,\.txt,.,' \
+                     -e 's,.patch,.,g' \
+                     -e 's,.diff,.,g' \
+                     -e 's,\.\.,.,g' \
+                     -e 's,\.$,,g' )
+
+    # ISSUE-branch-##
+    PATCH_BRANCH=$(echo "${patchnamechunk}" | cut -f3- -d- | cut -f1,2 -d-)
+    yetus_debug "Determine branch: ISSUE-branch-## = ${PATCH_BRANCH}"
+    if [[ -n "${PATCH_BRANCH}" ]]; then
+      verify_valid_branch  "${PATCH_BRANCH}"
+      if [[ $? == 0 ]]; then
+        return 0
+      fi
+    fi
+
+    # ISSUE-##[.##].branch
+    PATCH_BRANCH=$(echo "${patchnamechunk}" | cut -f3- -d. )
+    count="${PATCH_BRANCH//[^.]}"
+    total=${#count}
+    ((total = total + 3 ))
+    until [[ ${total} -lt 3 ]]; do
+      PATCH_BRANCH=$(echo "${patchnamechunk}" | cut -f3-${total} -d.)
+      yetus_debug "Determine branch: ISSUE[.##].branch = ${PATCH_BRANCH}"
+      ((total=total-1))
+      if [[ -n "${PATCH_BRANCH}" ]]; then
+        verify_valid_branch  "${PATCH_BRANCH}"
+        if [[ $? == 0 ]]; then
+          return 0
+        fi
+      fi
+    done
+
+    # ISSUE.branch.##
+    PATCH_BRANCH=$(echo "${patchnamechunk}" | cut -f2- -d. )
+    count="${PATCH_BRANCH//[^.]}"
+    total=${#count}
+    ((total = total + 3 ))
+    until [[ ${total} -lt 2 ]]; do
+      PATCH_BRANCH=$(echo "${patchnamechunk}" | cut -f2-${total} -d.)
+      yetus_debug "Determine branch: ISSUE.branch[.##] = ${PATCH_BRANCH}"
+      ((total=total-1))
+      if [[ -n "${PATCH_BRANCH}" ]]; then
+        verify_valid_branch  "${PATCH_BRANCH}"
+        if [[ $? == 0 ]]; then
+          return 0
+        fi
+      fi
+    done
+
+    # ISSUE-branch.##
+    PATCH_BRANCH=$(echo "${patchnamechunk}" | cut -f3- -d- | cut -f1- -d. )
+    count="${PATCH_BRANCH//[^.]}"
+    total=${#count}
+    ((total = total + 1 ))
+    until [[ ${total} -lt 1 ]]; do
+      PATCH_BRANCH=$(echo "${patchnamechunk}" | cut -f3- -d- | cut -f1-${total} -d. )
+      yetus_debug "Determine branch: ISSUE-branch[.##] = ${PATCH_BRANCH}"
+      ((total=total-1))
+      if [[ -n "${PATCH_BRANCH}" ]]; then
+        verify_valid_branch  "${PATCH_BRANCH}"
+        if [[ $? == 0 ]]; then
+          return 0
+        fi
+      fi
+    done
+  done
+
+  return 1
+}
+
+## @description Write the contents of a file to JIRA
+## @params filename
+## @stability stable
+## @audience public
+## @returns exit code from posting to jira
+function jira_write_comment
+{
+  declare -r commentfile=${1}
+  declare retval=0
+
+  if [[ "${OFFLINE}" == true ]]; then
+    echo "JIRA Plugin: Running in offline, comment skipped."
+    return 0
+  fi
+
+  if [[ -n ${JIRA_PASSWD}
+     && -n ${JIRA_USER} ]]; then
+
+    # RESTify the comment
+    {
+      echo "{\"body\":\""
+      ${SED} -e 's,\\,\\\\,g' \
+          -e 's,\",\\\",g' \
+          -e 's,$,\\r\\n,g' "${commentfile}" \
+      | tr -d '\n'
+      echo "\"}"
+    } > "${PATCH_DIR}/jiracomment.$$"
+
+    ${CURL} -X POST \
+         -H "Accept: application/json" \
+         -H "Content-Type: application/json" \
+         -u "${JIRA_USER}:${JIRA_PASSWD}" \
+         -d @"${PATCH_DIR}/jiracomment.$$" \
+         --silent --location \
+           "${JIRA_URL}/rest/api/2/issue/${JIRA_ISSUE}/comment" \
+          >/dev/null
+    retval=$?
+    rm "${PATCH_DIR}/jiracomment.$$"
+  else
+    echo "JIRA Plugin: no credentials provided to write a comment."
+  fi
+  return ${retval}
+}
+
+## @description  Print out the finished details to the JIRA issue
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        runresult
+function jira_finalreport
+{
+  declare result=$1
+  declare i
+  declare commentfile=${PATCH_DIR}/jiracommentfile
+  declare comment
+  declare vote
+  declare ourstring
+  declare ela
+  declare subs
+  declare color
+  declare comment
+
+  rm "${commentfile}" 2>/dev/null
+
+  if [[ ${JENKINS} == "false"
+      || ${OFFLINE} == true ]] ; then
+    return 0
+  fi
+
+  if [[ -z "${JIRA_ISSUE}" ]]; then
+    return 0
+  fi
+
+  big_console_header "Adding comment to JIRA"
+
+  add_footer_table "Console output" "${BUILD_URL}console"
+
+  if [[ ${result} == 0 ]]; then
+    echo "| (/) *{color:green}+1 overall{color}* |" >> "${commentfile}"
+  else
+    echo "| (x) *{color:red}-1 overall{color}* |" >> "${commentfile}"
+  fi
+
+  echo "\\\\" >>  "${commentfile}"
+
+  i=0
+  until [[ $i -eq ${#TP_HEADER[@]} ]]; do
+    printf "%s\n" "${TP_HEADER[${i}]}" >> "${commentfile}"
+    ((i=i+1))
+  done
+
+  echo "\\\\" >>  "${commentfile}"
+
+  echo "|| Vote || Subsystem || Runtime || Comment ||" >> "${commentfile}"
+
+  i=0
+  until [[ $i -eq ${#TP_VOTE_TABLE[@]} ]]; do
+    ourstring=$(echo "${TP_VOTE_TABLE[${i}]}" | tr -s ' ')
+    vote=$(echo "${ourstring}" | cut -f2 -d\| | tr -d ' ')
+    subs=$(echo "${ourstring}"  | cut -f3 -d\|)
+    ela=$(echo "${ourstring}" | cut -f4 -d\|)
+    comment=$(echo "${ourstring}"  | cut -f5 -d\|)
+
+    # summary line
+    if [[ -z ${vote}
+      && -n ${ela} ]]; then
+      color="black"
+    elif [[ -z ${vote} ]]; then
+      # keep same color
+      true
+    else
+      # new vote line
+      case ${vote} in
+        1|"+1")
+          color="green"
+        ;;
+        -1)
+          color="red"
+        ;;
+        0)
+          color="blue"
+        ;;
+        *)
+          color="black"
+        ;;
+      esac
+    fi
+
+    printf "| {color:%s}%s{color} | {color:%s}%s{color} | {color:%s}%s{color} | {color:%s}%s{color} |\n" \
+      "${color}" "${vote}" \
+      "${color}" "${subs}" \
+      "${color}" "${ela}" \
+      "${color}" "${comment}" \
+      >> "${commentfile}"
+    ((i=i+1))
+  done
+
+  if [[ ${#TP_TEST_TABLE[@]} -gt 0 ]]; then
+    { echo "\\\\" ; echo "\\\\"; } >>  "${commentfile}"
+
+    echo "|| Reason || Tests ||" >>  "${commentfile}"
+    i=0
+    until [[ $i -eq ${#TP_TEST_TABLE[@]} ]]; do
+      printf "%s\n" "${TP_TEST_TABLE[${i}]}" >> "${commentfile}"
+      ((i=i+1))
+    done
+  fi
+
+  { echo "\\\\" ; echo "\\\\"; } >>  "${commentfile}"
+
+  echo "|| Subsystem || Report/Notes ||" >> "${commentfile}"
+  i=0
+  until [[ $i -eq ${#TP_FOOTER_TABLE[@]} ]]; do
+    comment=$(echo "${TP_FOOTER_TABLE[${i}]}" |
+              ${SED} -e "s,@@BASE@@,${BUILD_URL}artifact/patchprocess,g")
+    printf "%s\n" "${comment}" >> "${commentfile}"
+    ((i=i+1))
+  done
+
+  printf "\n\nThis message was automatically generated.\n\n" >> "${commentfile}"
+
+  jira_write_comment "${commentfile}"
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/junit.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/junit.sh b/precommit/test-patch.d/junit.sh
new file mode 100755
index 0000000..4393511
--- /dev/null
+++ b/precommit/test-patch.d/junit.sh
@@ -0,0 +1,68 @@
+#!/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.
+
+add_test_format junit
+
+JUNIT_TEST_TIMEOUTS=""
+JUNIT_FAILED_TESTS=""
+
+function junit_process_tests
+{
+  # shellcheck disable=SC2034
+  declare module=$1
+  declare buildlogfile=$2
+  declare result=0
+  declare module_test_timeouts
+  declare module_failed_tests
+
+  # shellcheck disable=SC2016
+  module_test_timeouts=$(${AWK} '/^Running / { array[$NF] = 1 } /^Tests run: .* in / { delete array[$NF] } END { for (x in array) { print x } }' "${buildlogfile}")
+  if [[ -n "${module_test_timeouts}" ]] ; then
+    JUNIT_TEST_TIMEOUTS="${JUNIT_TEST_TIMEOUTS} ${module_test_timeouts}"
+    ((result=result+1))
+  fi
+
+  #shellcheck disable=SC2026,SC2038,SC2016
+  module_failed_tests=$(find . -name 'TEST*.xml'\
+    | xargs "${GREP}" -l -E "<failure|<error"\
+    | ${AWK} -F/ '{sub("TEST-org.apache.",""); sub(".xml",""); print $NF}')
+
+  if [[ -n "${module_failed_tests}" ]] ; then
+    JUNIT_FAILED_TESTS="${JUNIT_FAILED_TESTS} ${module_failed_tests}"
+    ((result=result+1))
+  fi
+
+  if [[ ${result} -gt 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+function junit_finalize_results
+{
+  declare jdk=$1
+
+  if [[ -n "${JUNIT_FAILED_TESTS}" ]] ; then
+    # shellcheck disable=SC2086
+    populate_test_table "${jdk}Failed junit tests" ${JUNIT_FAILED_TESTS}
+    JUNIT_FAILED_TESTS=""
+  fi
+  if [[ -n "${JUNIT_TEST_TIMEOUTS}" ]] ; then
+    # shellcheck disable=SC2086
+    populate_test_table "${jdk}Timed out junit tests" ${JUNIT_TEST_TIMEOUTS}
+    JUNIT_TEST_TIMEOUTS=""
+  fi
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/maven.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/maven.sh b/precommit/test-patch.d/maven.sh
new file mode 100755
index 0000000..019b64d
--- /dev/null
+++ b/precommit/test-patch.d/maven.sh
@@ -0,0 +1,440 @@
+#!/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.
+
+declare -a MAVEN_ARGS=("--batch-mode")
+
+if [[ -z "${MAVEN_HOME:-}" ]]; then
+  MAVEN=mvn
+else
+  MAVEN=${MAVEN_HOME}/bin/mvn
+fi
+
+MAVEN_CUSTOM_REPOS=false
+MAVEN_CUSTOM_REPOS_DIR="${HOME}/yetus-m2"
+
+add_test_type mvnsite
+add_test_type mvneclipse
+add_build_tool maven
+
+function maven_usage
+{
+  echo "maven specific:"
+  echo "--mvn-cmd=<cmd>            The 'mvn' command to use (default \${MAVEN_HOME}/bin/mvn, or 'mvn')"
+  echo "--mvn-custom-repos         Use per-project maven repos"
+  echo "--mvn-custom-repos-dir=dir Location of repos, default is \'${MAVEN_CUSTOM_REPOS_DIR}\'"
+  echo "--mvn-settings=file        File to use for settings.xml"
+}
+
+function maven_parse_args
+{
+  local i
+
+  for i in "$@"; do
+    case ${i} in
+      --mvn-cmd=*)
+        MAVEN=${i#*=}
+      ;;
+      --mvn-custom-repos)
+        MAVEN_CUSTOM_REPOS=true
+      ;;
+      --mvn-custom-repos-dir=*)
+        MAVEN_CUSTOM_REPOS_DIR=${i#*=}
+      ;;
+      --mvn-settings=*)
+        MAVEN_SETTINGS=${i#*=}
+        if [[ -f ${MAVEN_SETTINGS} ]]; then
+          MAVEN_ARGS=("${MAVEN_ARGS[@]}" "--settings=${MAVEN_SETTINGS}")
+        else
+          yetus_error "WARNING: ${MAVEN_SETTINGS} not found. Ignorning."
+        fi
+      ;;
+    esac
+  done
+
+  if [[ ${OFFLINE} == "true" ]]; then
+    MAVEN_ARGS=("${MAVEN_ARGS[@]}" --offline)
+  fi
+}
+
+function maven_initialize
+{
+  # we need to do this before docker does it as root
+
+  if [[ ! ${MAVEN_CUSTOM_REPOS_DIR} =~ ^/ ]]; then
+    yetus_error "ERROR: --mvn-custom-repos-dir must be an absolute path."
+    return 1
+  fi
+
+  if [[ ${MAVEN_CUSTOM_REPOS} = true ]]; then
+    MAVEN_LOCAL_REPO="${MAVEN_CUSTOM_REPOS_DIR}"
+    if [[ -e "${MAVEN_CUSTOM_REPOS_DIR}"
+       && ! -d "${MAVEN_CUSTOM_REPOS_DIR}" ]]; then
+      yetus_error "ERROR: ${MAVEN_CUSTOM_REPOS_DIR} is not a directory."
+      return 1
+    elif [[ ! -d "${MAVEN_CUSTOM_REPOS_DIR}" ]]; then
+      yetus_debug "Creating ${MAVEN_CUSTOM_REPOS_DIR}"
+      mkdir -p "${MAVEN_CUSTOM_REPOS_DIR}"
+    fi
+  fi
+
+  if [[ -e "${HOME}/.m2"
+     && ! -d "${HOME}/.m2" ]]; then
+    yetus_error "ERROR: ${HOME}/.m2 is not a directory."
+    return 1
+  elif [[ ! -e "${HOME}/.m2" ]]; then
+    yetus_debug "Creating ${HOME}/.m2"
+    mkdir -p "${HOME}/.m2"
+  fi
+}
+
+function maven_precheck
+{
+  declare logfile="${PATCH_DIR}/mvnrepoclean.log"
+  declare line
+
+  if [[ ! ${MAVEN_CUSTOM_REPOS_DIR} =~ ^/ ]]; then
+    yetus_error "ERROR: --mvn-custom-repos-dir must be an absolute path."
+    return 1
+  fi
+
+  if [[ ${MAVEN_CUSTOM_REPOS} = true ]]; then
+    MAVEN_LOCAL_REPO="${MAVEN_CUSTOM_REPOS_DIR}/${PROJECT_NAME}-${PATCH_BRANCH}-${INSTANCE}"
+    if [[ -e "${MAVEN_LOCAL_REPO}"
+       && ! -d "${MAVEN_LOCAL_REPO}" ]]; then
+      yetus_error "ERROR: ${MAVEN_LOCAL_REPO} is not a directory."
+      return 1
+    fi
+
+    if [[ ! -d "${MAVEN_LOCAL_REPO}" ]]; then
+      yetus_debug "Creating ${MAVEN_LOCAL_REPO}"
+      mkdir -p "${MAVEN_LOCAL_REPO}"
+      if [[ $? -ne 0 ]]; then
+        yetus_error "ERROR: Unable to create ${MAVEN_LOCAL_REPO}"
+        return 1
+      fi
+    fi
+    touch "${MAVEN_LOCAL_REPO}"
+
+    # if we have a local settings.xml file, we copy it.
+    if [[ -f "${HOME}/.m2/settings.xml" ]]; then
+      cp -p "${HOME}/.m2/settings.xml" "${MAVEN_LOCAL_REPO}"
+    fi
+    MAVEN_ARGS=("${MAVEN_ARGS[@]}" "-Dmaven.repo.local=${MAVEN_LOCAL_REPO}")
+
+    # let's do some cleanup while we're here
+
+    find "${MAVEN_CUSTOM_REPOS_DIR}" \
+      -name '*-*-*' \
+      -type d \
+      -mtime +30 \
+      -maxdepth 1 \
+      -print \
+        > "${logfile}"
+
+    while read -r line; do
+      echo "Removing old maven repo ${line}"
+      rm -rf "${line}"
+    done < "${logfile}"
+  fi
+}
+
+function maven_buildfile
+{
+  echo "pom.xml"
+}
+
+function maven_executor
+{
+  echo "${MAVEN}" "${MAVEN_ARGS[@]}"
+}
+
+function mvnsite_filefilter
+{
+  local filename=$1
+
+  if [[ ${BUILDTOOL} = maven ]]; then
+    if [[ ${filename} =~ src/site ]]; then
+       yetus_debug "tests/mvnsite: ${filename}"
+       add_test mvnsite
+     fi
+   fi
+}
+
+function maven_modules_worker
+{
+  declare repostatus=$1
+  declare tst=$2
+
+  # shellcheck disable=SC2034
+  UNSUPPORTED_TEST=false
+
+  case ${tst} in
+    findbugs)
+      modules_workers "${repostatus}" findbugs test-compile findbugs:findbugs -DskipTests=true
+    ;;
+    compile)
+      modules_workers "${repostatus}" compile clean test-compile -DskipTests=true
+    ;;
+    distclean)
+      modules_workers "${repostatus}" distclean clean -DskipTests=true
+    ;;
+    javadoc)
+      modules_workers "${repostatus}" javadoc clean javadoc:javadoc -DskipTests=true
+    ;;
+    scaladoc)
+      modules_workers "${repostatus}" scaladoc clean scala:doc -DskipTests=true
+    ;;
+    unit)
+      modules_workers "${repostatus}" unit clean test -fae
+    ;;
+    *)
+      # shellcheck disable=SC2034
+      UNSUPPORTED_TEST=true
+      if [[ ${repostatus} = patch ]]; then
+        add_footer_table "${tst}" "not supported by the ${BUILDTOOL} plugin"
+      fi
+      yetus_error "WARNING: ${tst} is unsupported by ${BUILDTOOL}"
+      return 1
+    ;;
+  esac
+}
+
+function maven_javac_count_probs
+{
+  local warningfile=$1
+
+  #shellcheck disable=SC2016,SC2046
+  ${GREP} '\[WARNING\]' "${warningfile}" | ${AWK} '{sum+=1} END {print sum}'
+}
+
+function maven_scalac_count_probs
+{
+  echo 0
+}
+
+## @description  Helper for check_patch_javadoc
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function maven_javadoc_count_probs
+{
+  local warningfile=$1
+
+  #shellcheck disable=SC2016,SC2046
+  ${GREP} -E "^[0-9]+ warnings?$" "${warningfile}" | ${AWK} '{sum+=$1} END {print sum}'
+}
+
+function maven_builtin_personality_modules
+{
+  local repostatus=$1
+  local testtype=$2
+
+  local module
+
+  yetus_debug "Using builtin personality_modules"
+  yetus_debug "Personality: ${repostatus} ${testtype}"
+
+  clear_personality_queue
+
+  # this always makes sure the local repo has a fresh
+  # copy of everything per pom rules.
+  if [[ ${repostatus} == branch
+     && ${testtype} == mvninstall ]];then
+     personality_enqueue_module .
+     return
+   fi
+
+  for module in ${CHANGED_MODULES}; do
+    # shellcheck disable=SC2086
+    personality_enqueue_module ${module}
+  done
+}
+
+function maven_builtin_personality_file_tests
+{
+  local filename=$1
+
+  yetus_debug "Using builtin mvn personality_file_tests"
+
+  if [[ ${filename} =~ src/main/webapp ]]; then
+    yetus_debug "tests/webapp: ${filename}"
+  elif [[ ${filename} =~ \.sh
+       || ${filename} =~ \.cmd
+       || ${filename} =~ src/main/scripts
+       || ${filename} =~ src/test/scripts
+       ]]; then
+    yetus_debug "tests/shell: ${filename}"
+  elif [[ ${filename} =~ \.c$
+       || ${filename} =~ \.cc$
+       || ${filename} =~ \.h$
+       || ${filename} =~ \.hh$
+       || ${filename} =~ \.proto$
+       || ${filename} =~ \.cmake$
+       || ${filename} =~ CMakeLists.txt
+       ]]; then
+    yetus_debug "tests/units: ${filename}"
+    add_test cc
+    add_test unit
+  elif [[ ${filename} =~ \.scala$
+       || ${filename} =~ src/scala ]]; then
+    add_test scalac
+    add_test scaladoc
+    add_test unit
+  elif [[ ${filename} =~ build.xml$
+       || ${filename} =~ pom.xml$
+       || ${filename} =~ \.java$
+       || ${filename} =~ src/main
+       ]]; then
+      yetus_debug "tests/javadoc+units: ${filename}"
+      add_test javac
+      add_test javadoc
+      add_test unit
+  fi
+
+  if [[ ${filename} =~ src/test ]]; then
+    yetus_debug "tests"
+    add_test unit
+  fi
+
+  if [[ ${filename} =~ \.java$ ]]; then
+    add_test findbugs
+  fi
+}
+
+## @description  Confirm site pre-patch
+## @audience     private
+## @stability    stable
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function mvnsite_postcompile
+{
+  declare repostatus=$1
+  declare result=0
+
+  if [[ ${BUILDTOOL} != maven ]]; then
+    return 0
+  fi
+
+  verify_needed_test mvnsite
+  if [[ $? == 0 ]];then
+    return 0
+  fi
+
+  if [[ "${repostatus}" = branch ]]; then
+    big_console_header "Pre-patch ${PATCH_BRANCH} maven site verification"
+  else
+    big_console_header "Patch maven site verification"
+  fi
+
+
+  personality_modules "${repostatus}" mvnsite
+  modules_workers "${repostatus}" mvnsite clean site site:stage
+  result=$?
+  modules_messages "${repostatus}" mvnsite true
+  if [[ ${result} != 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+## @description  Make sure Maven's eclipse generation works.
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function mvneclipse_postcompile
+{
+  declare repostatus=$1
+  declare result=0
+
+  if [[ ${BUILDTOOL} != maven ]]; then
+    return 0
+  fi
+
+  verify_needed_test javac
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+
+  if [[ "${repostatus}" = branch ]]; then
+    big_console_header "Pre-patch ${PATCH_BRANCH} maven eclipse verification"
+  else
+    big_console_header "Patch maven eclipse verification"
+  fi
+
+  personality_modules "${repostatus}" mvneclipse
+  modules_workers "${repostatus}" mvneclipse eclipse:clean eclipse:eclipse
+  result=$?
+  modules_messages "${repostatus}" mvneclipse true
+  if [[ ${result} != 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+## @description  Verify mvn install works
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function maven_precompile
+{
+  declare repostatus=$1
+  declare result=0
+
+  if [[ ${BUILDTOOL} != maven ]]; then
+    return 0
+  fi
+
+  verify_needed_test javadoc
+  result=$?
+
+  verify_needed_test javac
+  ((result = result + $? ))
+  if [[ ${result} == 0 ]]; then
+    return 0
+  fi
+
+  if [[ "${repostatus}" = branch ]]; then
+    big_console_header "Pre-patch ${PATCH_BRANCH} maven install"
+  else
+    big_console_header "Patch maven install"
+  fi
+
+  personality_modules "${repostatus}" mvninstall
+  modules_workers "${repostatus}" mvninstall -fae clean install -DskipTests=true -Dmaven.javadoc.skip=true
+  result=$?
+  modules_messages "${repostatus}" mvninstall true
+  if [[ ${result} != 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+function maven_docker_support
+{
+  echo "-v ${HOME}/.m2:${HOME}/.m2" > "${PATCH_DIR}/buildtool-docker-params.txt"
+
+  if [[ ${MAVEN_CUSTOM_REPOS} = true ]]; then
+    echo "-v ${MAVEN_CUSTOM_REPOS_DIR}:${MAVEN_CUSTOM_REPOS_DIR}" \
+      >> "${PATCH_DIR}/buildtool-docker-params.txt"
+  fi
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/nobuild.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/nobuild.sh b/precommit/test-patch.d/nobuild.sh
new file mode 100644
index 0000000..74d35aa
--- /dev/null
+++ b/precommit/test-patch.d/nobuild.sh
@@ -0,0 +1,55 @@
+#!/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.
+
+add_build_tool nobuild
+
+function nobuild_buildfile
+{
+  echo
+}
+
+function nobuild_executor
+{
+  echo "true"
+}
+
+function nobuild_modules_worker
+{
+  local status=$1
+  local testtype=$2
+  modules_workers "${status}" "${testtype}"
+}
+
+function nobuild_builtin_personality_modules
+{
+  local status=$1
+  local testtype=$2
+  yetus_debug "built-in personality for no build system: ${status} ${testtype}"
+
+  clear_personality_queue
+  for module in ${CHANGED_MODULES}; do
+    # shellcheck disable=SC2086
+    personality_enqueue_module ${module}
+  done
+}
+
+function nobuild_builtin_personality_file_tests
+{
+  local filename=$1
+
+  yetus_debug "Using built-in no build system personality_file_tests."
+  yetus_debug "    given file ${filename}"
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/perlcritic.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/perlcritic.sh b/precommit/test-patch.d/perlcritic.sh
new file mode 100755
index 0000000..c55f01a
--- /dev/null
+++ b/precommit/test-patch.d/perlcritic.sh
@@ -0,0 +1,151 @@
+#!/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.
+
+add_test_type perlcritic
+
+PERLCRITIC_TIMER=0
+
+PERLCRITIC=${PERLCRITIC:-$(which perlcritic 2>/dev/null)}
+
+function perlcritic_usage
+{
+  echo "Perl::Critic specific:"
+  echo "--perlcritic=<path> path to perlcritic executable"
+}
+
+function perlcritic_parse_args
+{
+  local i
+
+  for i in "$@"; do
+    case ${i} in
+    --perlcritic=*)
+      PERLCRITIC=${i#*=}
+    ;;
+    esac
+  done
+}
+
+function perlcritic_filefilter
+{
+  local filename=$1
+
+  if [[ ${filename} =~ \.p[lm]$ ]]; then
+    add_test perlcritic
+  fi
+}
+
+function perlcritic_preapply
+{
+  local i
+
+  verify_needed_test perlcritic
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+
+  big_console_header "Perl::Critic plugin: prepatch"
+
+  if [[ ! -x ${PERLCRITIC} ]]; then
+    yetus_error "${PERLCRITIC} does not exist."
+    return 0
+  fi
+
+  start_clock
+
+  echo "Running perlcritic against modified perl scripts/modules."
+  pushd "${BASEDIR}" >/dev/null
+  for i in ${CHANGED_FILES}; do
+    if [[ ${i} =~ \.p[lm]$ && -f ${i} ]]; then
+      ${PERLCRITIC} -1 --verbose 1 "${i}" 2>/dev/null >> "${PATCH_DIR}/branch-perlcritic-result.txt"
+    fi
+  done
+  popd >/dev/null
+  # keep track of how much as elapsed for us already
+  PERLCRITIC_TIMER=$(stop_clock)
+  return 0
+}
+
+function perlcritic_postapply
+{
+  local i
+  local numPrepatch
+  local numPostpatch
+  local diffPostpatch
+
+  verify_needed_test perlcritic
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+
+  big_console_header "Perl::Critic plugin: postpatch"
+
+  if [[ ! -x ${PERLCRITIC} ]]; then
+    yetus_error "${PERLCRITIC} is not available."
+    add_vote_table 0 perlcritic "Perl::Critic was not available."
+    return 0
+  fi
+
+  start_clock
+
+  # add our previous elapsed to our new timer
+  # by setting the clock back
+  offset_clock "${PERLCRITIC_TIMER}"
+
+  echo "Running perlcritic against modified perl scripts/modules."
+  # we re-check this in case one has been added
+  pushd "${BASEDIR}" >/dev/null
+  for i in ${CHANGED_FILES}; do
+    if [[ ${i} =~ \.p[lm]$ && -f ${i} ]]; then
+      ${PERLCRITIC} -1 --verbose 1 "${i}" 2>/dev/null >> "${PATCH_DIR}/patch-perlcritic-result.txt"
+    fi
+  done
+  popd >/dev/null
+
+  PERLCRITIC_VERSION=$(${PERLCRITIC} --version 2>/dev/null)
+  add_footer_table perlcritic "v${PERLCRITIC_VERSION}"
+
+  calcdiffs "${PATCH_DIR}/branch-perlcritic-result.txt" "${PATCH_DIR}/patch-perlcritic-result.txt" > "${PATCH_DIR}/diff-patch-perlcritic.txt"
+  # shellcheck disable=SC2016
+  diffPostpatch=$(wc -l "${PATCH_DIR}/diff-patch-perlcritic.txt" | ${AWK} '{print $1}')
+
+  if [[ ${diffPostpatch} -gt 0 ]] ; then
+    # shellcheck disable=SC2016
+    numPrepatch=$(wc -l "${PATCH_DIR}/branch-perlcritic-result.txt" | ${AWK} '{print $1}')
+
+    # shellcheck disable=SC2016
+    numPostpatch=$(wc -l "${PATCH_DIR}/patch-perlcritic-result.txt" | ${AWK} '{print $1}')
+
+    add_vote_table -1 perlcritic "The applied patch generated "\
+      "${diffPostpatch} new Perl::Critic issues (total was ${numPrepatch}, now ${numPostpatch})."
+    add_footer_table perlcritic "@@BASE@@/diff-patch-perlcritic.txt"
+    return 1
+  fi
+
+  add_vote_table +1 perlcritic "There were no new perlcritic issues."
+  return 0
+}
+
+function perlcritic_postcompile
+{
+  declare repostatus=$1
+
+  if [[ "${repostatus}" = branch ]]; then
+    perlcritic_preapply
+  else
+    perlcritic_postapply
+  fi
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/yetus/blob/6f38afa5/precommit/test-patch.d/pylint.sh
----------------------------------------------------------------------
diff --git a/precommit/test-patch.d/pylint.sh b/precommit/test-patch.d/pylint.sh
new file mode 100755
index 0000000..d5af000
--- /dev/null
+++ b/precommit/test-patch.d/pylint.sh
@@ -0,0 +1,179 @@
+#!/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.
+
+add_test_type pylint
+
+PYLINT_TIMER=0
+
+PYLINT=${PYLINT:-$(which pylint 2>/dev/null)}
+PYLINT_OPTIONS=${PYLINT_OPTIONS:-}
+
+function pylint_usage
+{
+  echo "Pylint specific:"
+  echo "--pylint=<path>         path to pylint executable"
+  echo "--pylint-options=<path> pylint options other than output-format and reports"
+}
+
+function pylint_parse_args
+{
+  local i
+
+  for i in "$@"; do
+    case ${i} in
+    --pylint=*)
+      PYLINT=${i#*=}
+    ;;
+    --pylint-options=*)
+      PYLINT_OPTIONS=${i#*=}
+    ;;
+    esac
+  done
+}
+
+function pylint_filefilter
+{
+  local filename=$1
+
+  if [[ ${filename} =~ \.py$ ]]; then
+    add_test pylint
+  fi
+}
+
+function pylint_preapply
+{
+  local i
+  local count
+  local tmp=${PATCH_DIR}/pylint.$$.${RANDOM}
+
+  verify_needed_test pylint
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+
+  big_console_header "pylint plugin: prepatch"
+
+  if [[ ! -x ${PYLINT} ]]; then
+    yetus_error "${PYLINT} does not exist."
+    return 0
+  fi
+
+  start_clock
+
+  echo "Running pylint against modified python scripts."
+  pushd "${BASEDIR}" >/dev/null
+  for i in ${CHANGED_FILES}; do
+    if [[ ${i} =~ \.py$ && -f ${i} ]]; then
+      # shellcheck disable=SC2086
+      eval "${PYLINT} ${PYLINT_OPTIONS} --output-format=parseable --reports=n ${i}" 2>${tmp} |
+      ${AWK} '1<NR' >> "${PATCH_DIR}/branch-pylint-result.txt"
+    fi
+    # shellcheck disable=SC2016
+    count=$(${GREP} -v "^No config file found" "${tmp}" | wc -l | ${AWK} '{print $1}')
+    if [[ ${count} -gt 0 ]]; then
+      add_footer_table pylint "prepatch stderr: ${tmp}"
+      return 1
+    fi
+  done
+  rm "${tmp}" 2>/dev/null
+  popd >/dev/null
+  # keep track of how much as elapsed for us already
+  PYLINT_TIMER=$(stop_clock)
+  return 0
+}
+
+function pylint_postapply
+{
+  local i
+  local count
+  local numPrepatch
+  local numPostpatch
+  local diffPostpatch
+  local tmp=${PATCH_DIR}/pylint.$$.${RANDOM}
+
+  verify_needed_test pylint
+  if [[ $? == 0 ]]; then
+    return 0
+  fi
+
+  big_console_header "pylint plugin: postpatch"
+
+  if [[ ! -x ${PYLINT} ]]; then
+    yetus_error "${PYLINT} is not available."
+    add_vote_table 0 pylint "Pylint was not available."
+    return 0
+  fi
+
+  start_clock
+
+  # add our previous elapsed to our new timer
+  # by setting the clock back
+  offset_clock "${PYLINT_TIMER}"
+
+  echo "Running pylint against modified python scripts."
+  # we re-check this in case one has been added
+  pushd "${BASEDIR}" >/dev/null
+  for i in ${CHANGED_FILES}; do
+    if [[ ${i} =~ \.py$ && -f ${i} ]]; then
+      # shellcheck disable=SC2086
+      eval "${PYLINT} ${PYLINT_OPTIONS} --output-format=parseable --reports=n ${i}" 2>${tmp} |
+      ${AWK} '1<NR' >> "${PATCH_DIR}/patch-pylint-result.txt"
+    fi
+    # shellcheck disable=SC2016
+    count=$(${GREP} -v "^No config file found" "${tmp}" | wc -l | ${AWK} '{print $1}')
+    if [[ ${count} -gt 0 ]]; then
+      add_vote_table -1 pylint "Something bad seems to have happened in running pylint. Please check pylint stderr files."
+      add_footer_table pylint "postpatch stderr: ${tmp}"
+      return 1
+    fi
+  done
+  rm "${tmp}" 2>/dev/null
+  popd >/dev/null
+
+  # shellcheck disable=SC2016
+  PYLINT_VERSION=$(${PYLINT} --version 2>/dev/null | ${GREP} pylint | ${AWK} '{print $NF}')
+  add_footer_table pylint "v${PYLINT_VERSION%,}"
+
+  calcdiffs "${PATCH_DIR}/branch-pylint-result.txt" "${PATCH_DIR}/patch-pylint-result.txt" > "${PATCH_DIR}/diff-patch-pylint.txt"
+  diffPostpatch=$(${GREP} -c "^.*:.*: \[.*\] " "${PATCH_DIR}/diff-patch-pylint.txt")
+
+  if [[ ${diffPostpatch} -gt 0 ]] ; then
+    # shellcheck disable=SC2016
+    numPrepatch=$(${GREP} -c "^.*:.*: \[.*\] " "${PATCH_DIR}/branch-pylint-result.txt")
+
+    # shellcheck disable=SC2016
+    numPostpatch=$(${GREP} -c "^.*:.*: \[.*\] " "${PATCH_DIR}/patch-pylint-result.txt")
+
+    add_vote_table -1 pylint "The applied patch generated "\
+      "${diffPostpatch} new pylint issues (total was ${numPrepatch}, now ${numPostpatch})."
+    add_footer_table pylint "@@BASE@@/diff-patch-pylint.txt"
+    return 1
+  fi
+
+  add_vote_table +1 pylint "There were no new pylint issues."
+  return 0
+}
+
+function pylint_postcompile
+{
+  declare repostatus=$1
+
+  if [[ "${repostatus}" = branch ]]; then
+    pylint_preapply
+  else
+    pylint_postapply
+  fi
+}


Mime
View raw message