yetus-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a.@apache.org
Subject [13/17] yetus git commit: YETUS-15. build environment
Date Sun, 11 Nov 2018 22:19:29 GMT
http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/personality/tajo.sh
----------------------------------------------------------------------
diff --git a/precommit/personality/tajo.sh b/precommit/personality/tajo.sh
deleted file mode 100755
index fb86ff7..0000000
--- a/precommit/personality/tajo.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/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.
-
-personality_plugins "all"
-
-## @description  Globals specific to this personality
-## @audience     private
-## @stability    evolving
-function personality_globals
-{
-  # shellcheck disable=SC2034
-  BUILDTOOL=maven
-  #shellcheck disable=SC2034
-  PATCH_BRANCH_DEFAULT=master
-  #shellcheck disable=SC2034
-  JIRA_ISSUE_RE='^TAJO-[0-9]+$'
-  #shellcheck disable=SC2034
-  GITHUB_REPO="apache/tajo"
-  #shellcheck disable=SC2034
-  PATCH_NAMING_RULE="https://cwiki.apache.org/confluence/display/TAJO/How+to+Contribute+to+Tajo"
-}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/personality/tez.sh
----------------------------------------------------------------------
diff --git a/precommit/personality/tez.sh b/precommit/personality/tez.sh
deleted file mode 100755
index 32d9ffc..0000000
--- a/precommit/personality/tez.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/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.
-
-personality_plugins "all"
-
-## @description  Globals specific to this personality
-## @audience     private
-## @stability    evolving
-function personality_globals
-{
-  # shellcheck disable=SC2034
-  BUILDTOOL=maven
-  #shellcheck disable=SC2034
-  PATCH_BRANCH_DEFAULT=master
-  #shellcheck disable=SC2034
-  JIRA_ISSUE_RE='^TEZ-[0-9]+$'
-  #shellcheck disable=SC2034
-  GITHUB_REPO="apache/tez"
-  #shellcheck disable=SC2034
-  PATCH_NAMING_RULE="https://cwiki.apache.org/confluence/display/TEZ/How+to+Contribute+to+Tez"
-}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/pom.xml
----------------------------------------------------------------------
diff --git a/precommit/pom.xml b/precommit/pom.xml
new file mode 100644
index 0000000..1c11a8b
--- /dev/null
+++ b/precommit/pom.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.yetus</groupId>
+    <artifactId>yetus-project</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+  <artifactId>precommit</artifactId>
+  <description>Build and Patch Management and Testing</description>
+  <name>Apache Yetus - Precommit</name>
+  <packaging>pom</packaging>
+
+  <build>
+    <plugins>
+
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>mkdir-bin</id>
+            <phase>initialize</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <configuration>
+              <exportAntProperties>true</exportAntProperties>
+              <target>
+                <mkdir dir="target/dist/apache-yetus-${project.version}/lib/${project.artifactId}"/>
+                <mkdir dir="target/dist/apache-yetus-${project.version}/bin"/>
+              </target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.yetus</groupId>
+            <artifactId>yetus-assemblies</artifactId>
+            <version>${project.version}</version>
+          </dependency>
+        </dependencies>
+        <executions>
+          <execution>
+            <id>build</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+            <configuration>
+              <finalName>dist/apache-yetus-${project.version}</finalName>
+              <appendAssemblyId>false</appendAssemblyId>
+              <attach>false</attach>
+              <descriptorRefs>
+                <descriptorRef>script-bundle</descriptorRef>
+              </descriptorRefs>
+            </configuration>
+          </execution>
+
+          <execution>
+            <id>module-dist</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+            <configuration>
+              <appendAssemblyId>false</appendAssemblyId>
+              <attach>true</attach>
+              <descriptorRefs>
+                <descriptorRef>module-dist</descriptorRef>
+              </descriptorRefs>
+            </configuration>
+          </execution>
+
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.yetus</groupId>
+        <artifactId>yetus-minimaven-plugin</artifactId>
+        <version>${project.version}</version>
+        <executions>
+          <execution>
+            <id>qbt.sh</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>symlink</goal>
+            </goals>
+            <configuration>
+              <target>test-patch.sh</target>
+              <newLink>dist/apache-yetus-${project.version}/lib/${project.artifactId}/qbt.sh</newLink>
+            </configuration>
+          </execution>
+          <execution>
+            <id>bins4libs</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>bin4libs</goal>
+            </goals>
+            <configuration>
+              <libdir>lib/precommit</libdir>
+              <basedir>${project.build.directory}/dist/apache-yetus-${project.version}</basedir>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>src/main/python/unit-test-filter-file.example</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+
+    </plugins>
+  </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/smart-apply-patch.sh
----------------------------------------------------------------------
diff --git a/precommit/smart-apply-patch.sh b/precommit/smart-apply-patch.sh
deleted file mode 100755
index a5dd09b..0000000
--- a/precommit/smart-apply-patch.sh
+++ /dev/null
@@ -1,333 +0,0 @@
-#!/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.
-
-# Make sure that bash version meets the pre-requisite
-
-if [[ -z "${BASH_VERSINFO[0]}" ]] \
-   || [[ "${BASH_VERSINFO[0]}" -lt 3 ]] \
-   || [[ "${BASH_VERSINFO[0]}" -eq 3 && "${BASH_VERSINFO[1]}" -lt 2 ]]; then
-  echo "bash v3.2+ is required. Sorry."
-  exit 1
-fi
-
-this="${BASH_SOURCE-$0}"
-BINDIR=$(cd -P -- "$(dirname -- "${this}")" >/dev/null && pwd -P)
-#shellcheck disable=SC2034
-QATESTMODE=false
-
-# dummy functions
-function add_vote_table
-{
-  true
-}
-
-function add_footer_table
-{
-  true
-}
-
-function big_console_header
-{
-  true
-}
-
-function add_test
-{
-  true
-}
-
-## @description  Clean the filesystem as appropriate and then exit
-## @audience     private
-## @stability    evolving
-## @replaceable  no
-## @param        runresult
-function cleanup_and_exit
-{
-  local result=$1
-
-  if [[ ${PATCH_DIR} =~ ^/tmp/yetus
-    && -d ${PATCH_DIR} ]]; then
-    rm -rf "${PATCH_DIR}"
-  fi
-
-  # shellcheck disable=SC2086
-  exit ${result}
-}
-
-## @description  Setup the default global variables
-## @audience     public
-## @stability    stable
-## @replaceable  no
-function setup_defaults
-{
-  common_defaults
-}
-
-## @description  Print the usage information
-## @audience     public
-## @stability    stable
-## @replaceable  no
-function yetus_usage
-{
-  echo "smart-apply-patch.sh [OPTIONS] patch"
-  echo ""
-  echo "Where:"
-  echo "  patch is a file, URL, or bugsystem-compatible location of the patch file"
-  echo ""
-  echo "Options:"
-  echo ""
-  yetus_add_option "--committer" "Apply patches like a boss."
-  yetus_add_option "--debug" "If set, then output some extra stuff to stderr"
-  yetus_add_option "--dry-run" "Check for patch viability without applying"
-  yetus_add_option "--list-plugins" "List all installed plug-ins and then exit"
-  yetus_add_option "--modulelist=<list>" "Specify additional modules to test (comma delimited)"
-  yetus_add_option "--offline" "Avoid connecting to the Internet"
-  yetus_add_option "--patch-dir=<dir>" "The directory for working and output files (default '/tmp/yetus-(random))"
-  yetus_add_option "--personality=<file>" "The personality file to load"
-  yetus_add_option "--plugins=<list>" "Specify which plug-ins to add/delete (comma delimited; use 'all' for all found)"
-  yetus_add_option "--project=<name>" "The short name for project currently using test-patch (default 'yetus')"
-  yetus_add_option "--skip-system-plugins" "Do not load plugins from ${BINDIR}/test-patch.d"
-  yetus_add_option "--user-plugins=<dir>" "A directory of user provided plugins. see test-patch.d for examples (default empty)"
-  yetus_add_option "--version" "Print release version information and exit"
-  yetus_add_option "--gpg-sign" "GPG sign the commit using gpg keys"
-  yetus_generic_columnprinter "${YETUS_OPTION_USAGE[@]}"
-  yetus_reset_usage
-
-  echo ""
-  echo "Shell binary overrides:"
-  yetus_add_option "--awk-cmd=<cmd>" "The 'awk' command to use (default 'awk')"
-  yetus_add_option "--curl-cmd=<cmd>" "The 'curl' command to use (default 'curl')"
-  yetus_add_option "--diff-cmd=<cmd>" "The GNU-compatible 'diff' command to use (default 'diff')"
-  yetus_add_option "--file-cmd=<cmd>" "The 'file' command to use (default 'file')"
-  yetus_add_option "--git-cmd=<cmd>" "The 'git' command to use (default 'git')"
-  yetus_add_option "--grep-cmd=<cmd>" "The 'grep' command to use (default 'grep')"
-  yetus_add_option "--patch-cmd=<cmd>" "The 'patch' command to use (default 'patch')"
-  yetus_add_option "--sed-cmd=<cmd>" "The 'sed' command to use (default 'sed')"
-  yetus_generic_columnprinter "${YETUS_OPTION_USAGE[@]}"
-  yetus_reset_usage
-
-  echo ""
-  importplugins
-
-  unset TESTFORMATS
-  unset TESTTYPES
-  unset BUILDTOOLS
-
-  for plugin in ${BUGSYSTEMS}; do
-    if declare -f ${plugin}_usage >/dev/null 2>&1; then
-      echo ""
-      echo "${plugin} plugin usage options:"
-      "${plugin}_usage"
-      yetus_generic_columnprinter "${YETUS_OPTION_USAGE[@]}"
-      yetus_reset_usage
-    fi
-  done
-}
-
-## @description  Interpret the command line parameters
-## @audience     private
-## @stability    stable
-## @replaceable  no
-## @param        $@
-## @return       May exit on failure
-function parse_args
-{
-  local i
-
-  common_args "$@"
-
-  for i in "$@"; do
-    case ${i} in
-      --committer)
-        COMMITMODE=true
-      ;;
-      --gpg-sign)
-        GPGSIGN=true
-      ;;
-      --dry-run)
-        PATCH_DRYRUNMODE=true
-      ;;
-      --*)
-        ## PATCH_OR_ISSUE can't be a --.  So this is probably
-        ## a plugin thing.
-        continue
-      ;;
-      *)
-        PATCH_OR_ISSUE=${i#*=}
-      ;;
-    esac
-  done
-
-  if [[ ! -d ${PATCH_DIR} ]]; then
-    mkdir -p "${PATCH_DIR}"
-    if [[ $? != 0 ]] ; then
-      yetus_error "ERROR: Unable to create ${PATCH_DIR}"
-      cleanup_and_exit 1
-    fi
-  fi
-}
-
-## @description  git am dryrun
-## @replaceable  no
-## @audience     private
-## @stability    evolving
-function gitam_dryrun
-{
-
-  # there is no dryrun method for git-am, so just
-  # use apply instead.
-  gitapply_dryrun "$@"
-
-  if [[ ${PATCH_METHOD} = "gitapply" ]]; then
-    PATCH_METHOD="gitam"
-  fi
-}
-
-## @description  git am signoff
-## @replaceable  no
-## @audience     private
-## @stability    evolving
-function gitam_apply
-{
-  declare patchfile=$1
-  declare gpg=$2
-
-  if [[ ${gpg} = true ]]; then
-    EXTRA_ARGS="-S"
-  fi
-
-  echo "Applying the patch:"
-  yetus_run_and_redirect "${PATCH_DIR}/apply-patch-git-am.log" \
-    "${GIT}" am --signoff ${EXTRA_ARGS} --whitespace=fix "-p${PATCH_LEVEL}" "${patchfile}"
-  RESULT=$?
-  ${GREP} -v "^Checking" "${PATCH_DIR}/apply-patch-git-am.log"
-
-  # fallback
-  if [[ ${RESULT} -gt 0 && ${PATCH_SYSTEM} == 'jira' ]]; then
-    echo "Use git apply and commit with the information from jira."
-    gitapply_and_commit "${patchfile}"
-  fi
-}
-
-## @description  get author and summary from jira and commit it.
-##               if the author and the summary contains " or *,
-##               the function does not work correctly because
-##               the characters are used for delimiters.
-## @replaceable  no
-## @audience     private
-## @stability    evolving
-function gitapply_and_commit
-{
-  declare patchfile=$1
-  declare jsontmpfile
-  declare assigneeline
-  declare assigneefile
-  declare name
-  declare email
-  declare author
-  declare summary
-
-  yetus_debug "gitapply_and_commit: fetching ${JIRA_URL}/rest/api/2/issue/${PATCH_OR_ISSUE}"
-  if ! jira_http_fetch "rest/api/2/issue/${PATCH_OR_ISSUE}" "${PATCH_DIR}/issue"; then
-    yetus_debug "gitapply_and_commit: not a JIRA."
-    return 1
-  fi
-
-  jsontmpfile="${PATCH_DIR}/jsontmpfile"
-  # cannot set " as delimiter for cut command in script, so replace " with *
-  tr ',' '\n' < "${PATCH_DIR}/issue" | ${SED} 's/\"/*/g' > "${jsontmpfile}"
-
-  assigneeline=$(${GREP} -n -E "^\*assignee\*:" "${jsontmpfile}" | cut -f1 -d":")
-  assigneefile="${PATCH_DIR}/assigneefile"
-  tail -n +"${assigneeline}" "${jsontmpfile}" | head -n 20 > "${assigneefile}"
-
-  name=$(${GREP} "displayName" "${assigneefile}" | cut -f4 -d"*")
-  email=$(${GREP} "emailAddress" "${assigneefile}" | cut -f4 -d"*" \
-    | ${SED} 's/ at /@/g' | ${SED} 's/ dot /./g')
-  author="${name} <${email}>"
-  summary=$(${GREP} -E "^\*summary\*:" "${jsontmpfile}" | cut -f4 -d"*")
-  gitapply_apply "${patchfile}"
-  ${GIT} add --all
-  echo "Committing with author: ${author}, summary: ${summary}"
-  yetus_run_and_redirect "${PATCH_DIR}/apply-patch-git-am-fallback.log" \
-    "${GIT}" commit ${EXTRA_ARGS} --signoff -m "${PATCH_OR_ISSUE}. ${summary}" \
-    --author="${author}"
-}
-
-## @description import core library routines
-## @audience private
-## @stability evolving
-function import_core
-{
-  declare filename
-
-  for filename in "${BINDIR}/core.d"/*; do
-    # shellcheck disable=SC1091
-    # shellcheck source=core.d/01-common.sh
-    . "${filename}"
-  done
-}
-
-trap "cleanup_and_exit 1" HUP INT QUIT TERM
-
-import_core
-
-setup_defaults
-
-parse_args "$@"
-
-importplugins
-yetus_debug "Removing BUILDTOOLS, TESTTYPES, and TESTFORMATS from installed plug-in list"
-unset BUILDTOOLS
-unset TESTTYPES
-unset TESTFORMATS
-
-parse_args_plugins "$@"
-
-plugins_initialize
-
-locate_patch
-
-if [[ ${COMMITMODE} = true ]]; then
-  status=$(${GIT} status --porcelain)
-  if [[ "$status" != "" ]] ; then
-    yetus_error "ERROR: Can't use --committer option in a workspace that contains the following modifications:"
-    yetus_error "${status}"
-    cleanup_and_exit 1
-  fi
-  PATCH_METHODS=("gitam" "${PATCH_METHODS[@]}")
-fi
-
-patchfile_dryrun_driver "${PATCH_DIR}/patch"
-RESULT=$?
-
-if [[ ${RESULT} -gt 0 ]]; then
-  yetus_error "ERROR: Aborting! ${PATCH_OR_ISSUE} cannot be verified."
-  cleanup_and_exit ${RESULT}
-fi
-
-if [[ ${PATCH_DRYRUNMODE} == false ]]; then
-  patchfile_apply_driver "${PATCH_DIR}/patch" "${GPGSIGN}"
-  RESULT=$?
-fi
-
-if [[ ${COMMITMODE} = true
-   && ${PATCH_METHOD} != "gitam" ]]; then
-  yetus_debug "Running git add -A"
-  git add -A
-fi
-
-cleanup_and_exit ${RESULT}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/python/jenkins-admin.py
----------------------------------------------------------------------
diff --git a/precommit/src/main/python/jenkins-admin.py b/precommit/src/main/python/jenkins-admin.py
new file mode 100755
index 0000000..f6ffdfe
--- /dev/null
+++ b/precommit/src/main/python/jenkins-admin.py
@@ -0,0 +1,245 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+from optparse import OptionParser
+from tempfile import NamedTemporaryFile
+from xml.etree import ElementTree
+import base64
+import httplib
+import os
+import re
+import sys
+import urllib2
+
+def httpGet(resource, ignoreError=False, username=None, password=None):
+    request = urllib2.Request(resource)
+    if username and password:
+      base64string = base64.b64encode('%s:%s' % (username, password))
+      request.add_header("Authorization", "Basic %s" % base64string)
+    try:
+        response = urllib2.urlopen(request)
+    except urllib2.HTTPError, http_err:
+        code = http_err.code
+        print '%s returns HTTP error %d: %s' \
+              % (resource, code, http_err.reason)
+        if ignoreError:
+            return ''
+        else:
+            print 'Aborting.'
+            sys.exit(1)
+    except urllib2.URLError, url_err:
+        print 'Error contacting %s: %s' % (resource, url_err.reason)
+        if ignoreError:
+            return ''
+        else:
+            raise url_err
+    except httplib.BadStatusLine, err:
+        if ignoreError:
+            return ''
+        else:
+            raise err
+    return response.read()
+
+
+# returns a map of (project, issue) => attachment id
+
+def parseJiraData(fileName):
+    tree = ElementTree.parse(fileName)
+    root = tree.getroot()
+    jiraPattern = re.compile('([A-Z]+)\-([0-9]+)')
+    result = {}
+    for item in root.findall('./channel/item'):
+        jirakey = item.find('key')
+        if jirakey is None:
+            continue
+        jiraissue = jirakey.text
+        matcher = jiraPattern.match(jiraissue)
+        if not matcher:
+            continue
+        jiraissue = (matcher.group(1), matcher.group(2))
+        attachmentIds = []
+        for jiraattachment in item.findall('./attachments/attachment'):
+            attachmentId = jiraattachment.get('id')
+            try:
+                attachmentIds.append(int(attachmentId))
+            except ValueError:
+                pass
+        if attachmentIds:
+            attachmentIds.sort()
+            result[jiraissue] = attachmentIds[-1]
+    return result
+
+
+if __name__ == '__main__':
+    parser = OptionParser(prog = 'jenkins-admin')
+    if os.getenv('JENKINS_URL'):
+        parser.set_defaults(jenkinsUrl=os.getenv('JENKINS_URL'))
+    if os.getenv('JOB_NAME'):
+        parser.set_defaults(jenkinsJobName=os.getenv('JOB_NAME'))
+    else:
+        parser.set_defaults(jenkinsJobName='PreCommit-Admin')
+
+    parser.set_defaults(jenkinsJobTemplate='PreCommit-{project}')
+    parser.add_option('--initialize', action='store_true',
+                      dest='jenkinsInit',
+                      help='Start a new patch_tested.txt file')
+    parser.add_option('--jenkins-jobname', type='string',
+                      dest='jenkinsJobName',
+                      help='PreCommit-Admin JobName', metavar='JOB_NAME')
+    parser.add_option('--jenkins-project-template', type='string',
+                      dest='jenkinsJobTemplate',
+                      help='Template for project jobs',
+                      metavar='TEMPLATE')
+    parser.add_option('--jenkins-token', type='string',
+                      dest='jenkinsToken', help='Jenkins Token',
+                      metavar='TOKEN')
+    parser.add_option('--jenkins-url', type='string', dest='jenkinsUrl'
+                      , help='Jenkins base URL', metavar='URL')
+    parser.add_option(
+        '--jenkins-url-override',
+        type='string',
+        dest='jenkinsUrlOverrides',
+        action='append',
+        help='Project specific Jenkins base URL',
+        metavar='PROJECT=URL',
+        )
+    parser.add_option('--jira-filter', type='string', dest='jiraFilter',
+                      help='JIRA filter URL', metavar='URL')
+    parser.add_option('--jira-user', type='string', dest='jiraUser',
+                      help='JIRA username')
+    parser.add_option('--jira-password', type='string', dest='jiraPassword',
+                      help='JIRA password')
+    parser.add_option('--live', dest='live', action='store_true',
+                      help='Submit Job to jenkins')
+    parser.add_option('--max-history', dest='history', type='int',
+                      help='Maximum history to store', default=5000)
+    parser.add_option(
+        '-V',
+        '--version',
+        dest='release_version',
+        action='store_true',
+        default=False,
+        help="display version information for jenkins-admin and exit.")
+
+    (options, args) = parser.parse_args()
+
+    # Handle the version string right away and exit
+    if options.release_version:
+        with open(
+                os.path.join(
+                    os.path.dirname(__file__), "../../VERSION"), 'r') as ver_file:
+            print ver_file.read()
+        sys.exit(0)
+
+    tokenFrag = ''
+    if options.jenkinsToken:
+        tokenFrag = 'token=%s' % options.jenkinsToken
+    else:
+        tokenFrag = 'token={project}-token'
+    if not options.jiraFilter:
+        parser.error('ERROR: --jira-filter is a required argument.')
+    if not options.jenkinsUrl:
+        parser.error('ERROR: --jenkins-url or the JENKINS_URL environment variable is required.'
+                     )
+    if options.history < 0:
+        parser.error('ERROR: --max-history must be 0 or a positive integer.'
+                     )
+    jenkinsUrlOverrides = {}
+    if options.jenkinsUrlOverrides:
+        for override in options.jenkinsUrlOverrides:
+            if '=' not in override:
+                parser.error('Invalid Jenkins Url Override: '
+                             + override)
+            (project, url) = override.split('=', 1)
+            jenkinsUrlOverrides[project.upper()] = url
+    tempFile = NamedTemporaryFile(delete=False)
+    try:
+        jobLogHistory = None
+        if not options.jenkinsInit:
+            jobLogHistory = httpGet(options.jenkinsUrl
+                                    + '/job/%s/lastSuccessfulBuild/artifact/patch_tested.txt'
+                                     % options.jenkinsJobName, True)
+
+            # if we don't have a successful build available try the last build
+
+            if not jobLogHistory:
+                jobLogHistory = httpGet(options.jenkinsUrl
+                        + '/job/%s/lastCompletedBuild/artifact/patch_tested.txt'
+                         % options.jenkinsJobName)
+            jobLogHistory = jobLogHistory.strip().split('\n')
+            if 'TESTED ISSUES' not in jobLogHistory[0]:
+                print 'Downloaded patch_tested.txt control file may be corrupted. Failing.'
+                sys.exit(1)
+
+        # we are either going to write a new one or rewrite the old one
+
+        jobLog = open('patch_tested.txt', 'w+')
+
+        if jobLogHistory:
+            if len(jobLogHistory) > options.history:
+                jobLogHistory = [jobLogHistory[0]] \
+                    + jobLogHistory[len(jobLogHistory)
+                    - options.history:]
+            for jobHistoryRecord in jobLogHistory:
+                jobLog.write(jobHistoryRecord + '\n')
+        else:
+            jobLog.write('TESTED ISSUES\n')
+        jobLog.flush()
+        rssData = httpGet(options.jiraFilter,False,options.jiraUser,options.jiraPassword)
+        tempFile.write(rssData)
+        tempFile.flush()
+        for (key, attachment) in parseJiraData(tempFile.name).items():
+            (project, issue) = key
+            if jenkinsUrlOverrides.has_key(project):
+                url = jenkinsUrlOverrides[project]
+            else:
+                url = options.jenkinsUrl
+
+            jenkinsUrlTemplate = url + '/job/' \
+                + options.jenkinsJobTemplate \
+                + '/buildWithParameters?' + tokenFrag \
+                + '&ISSUE_NUM={issue}&ATTACHMENT_ID={attachment}'
+
+            urlArgs = {
+                'project': project,
+                'issue': issue,
+                'attachment': attachment,
+                }
+            jenkinsUrl = jenkinsUrlTemplate.format(**urlArgs)
+
+            # submit job
+
+            jobName = '%s-%s,%s' % (project, issue, attachment)
+            if not jobLogHistory or jobName not in jobLogHistory:
+                print jobName + ' has not been processed, submitting'
+                jobLog.write(jobName + '\n')
+                jobLog.flush()
+                if options.live:
+                    httpGet(jenkinsUrl, True)
+                else:
+                    print 'GET ' + jenkinsUrl
+            else:
+                print jobName + ' has been processed, ignoring'
+        jobLog.close()
+    finally:
+        if options.live:
+            os.remove(tempFile.name)
+        else:
+            print 'JIRA Data is located: ' + tempFile.name

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/python/unit-test-filter-file.example
----------------------------------------------------------------------
diff --git a/precommit/src/main/python/unit-test-filter-file.example b/precommit/src/main/python/unit-test-filter-file.example
new file mode 100644
index 0000000..dc38859
--- /dev/null
+++ b/precommit/src/main/python/unit-test-filter-file.example
@@ -0,0 +1,2 @@
+[package].[class].[method]
+![package].[class].[method]

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/shell/coprocs.d/README.md
----------------------------------------------------------------------
diff --git a/precommit/src/main/shell/coprocs.d/README.md b/precommit/src/main/shell/coprocs.d/README.md
new file mode 100755
index 0000000..e960cad
--- /dev/null
+++ b/precommit/src/main/shell/coprocs.d/README.md
@@ -0,0 +1,25 @@
+#!/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.
+
+#############################
+##
+## bash v4+ coproc routines
+##
+#############################
+
+# bash v3 and lower will treat coproc commands as syntax errors
+# therefore, ALL functions which activate coprocs are located
+# here
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/shell/coprocs.d/e_a_r_helper.sh
----------------------------------------------------------------------
diff --git a/precommit/src/main/shell/coprocs.d/e_a_r_helper.sh b/precommit/src/main/shell/coprocs.d/e_a_r_helper.sh
new file mode 100755
index 0000000..3df8293
--- /dev/null
+++ b/precommit/src/main/shell/coprocs.d/e_a_r_helper.sh
@@ -0,0 +1,35 @@
+#!/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
+
+## @description helper function for echo_and_redirect
+## @audience private
+## @stability evolving
+## @replaceable no
+function e_a_r_helper
+{
+  declare logfile=$1
+  shift
+  declare params=("${@}")
+
+  echo "Launching yrr_coproc" >> "${COPROC_LOGFILE}"
+  # shellcheck disable=SC2034
+  coproc yrr_coproc {
+    ulimit -Su "${PROC_LIMIT}"
+    yetus_run_and_redirect "${logfile}" "${params[@]}"
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/shell/coprocs.d/process_counter.sh
----------------------------------------------------------------------
diff --git a/precommit/src/main/shell/coprocs.d/process_counter.sh b/precommit/src/main/shell/coprocs.d/process_counter.sh
new file mode 100755
index 0000000..4f944bb
--- /dev/null
+++ b/precommit/src/main/shell/coprocs.d/process_counter.sh
@@ -0,0 +1,48 @@
+#!/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
+
+function process_counter_coproc_start
+{
+  if [[ "${OSTYPE}" = Linux && "${DOCKERMODE}" = true ]]; then
+    # this is really only even remotely close to
+    # accurate under Docker, for the time being.
+
+    echo "Launching process_counter_coproc" >> "${COPROC_LOGFILE}"
+    # shellcheck disable=SC2034
+    coproc process_counter_coproc {
+      declare threadcount
+      declare maxthreadcount
+      declare cmd
+
+      sleep 2
+      while true; do
+        threadcount=$(ps -L -u "${USER_ID}" -o lwp 2>/dev/null | wc -l)
+        if [[ ${threadcount} -gt ${maxthreadcount} ]]; then
+          maxthreadcount="${threadcount}"
+          echo "${maxthreadcount}" > "${PATCH_DIR}/threadcounter.txt"
+        fi
+        read -r -t 2 cmd
+        case "${cmd}" in
+          exit)
+            exit 0
+          ;;
+        esac
+      done
+    }
+  fi
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/shell/coprocs.d/reaper.sh
----------------------------------------------------------------------
diff --git a/precommit/src/main/shell/coprocs.d/reaper.sh b/precommit/src/main/shell/coprocs.d/reaper.sh
new file mode 100755
index 0000000..4674130
--- /dev/null
+++ b/precommit/src/main/shell/coprocs.d/reaper.sh
@@ -0,0 +1,30 @@
+#!/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
+
+function reaper_coproc_start
+{
+  if [[ "${REAPER_MODE}" != "off" ]]; then
+
+    echo "Launching reaper_coproc" >> "${COPROC_LOGFILE}"
+
+    # shellcheck disable=SC2034
+    coproc reaper_coproc {
+      reaper_coproc_func
+    }
+  fi
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/shell/core.d/00-yetuslib.sh
----------------------------------------------------------------------
diff --git a/precommit/src/main/shell/core.d/00-yetuslib.sh b/precommit/src/main/shell/core.d/00-yetuslib.sh
new file mode 100755
index 0000000..983dfe6
--- /dev/null
+++ b/precommit/src/main/shell/core.d/00-yetuslib.sh
@@ -0,0 +1,331 @@
+#!/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.
+
+# we need to declare this globally as an array, which can only
+# be done outside of a function
+declare -a YETUS_OPTION_USAGE
+
+## @description  Print a message to stderr
+## @audience     public
+## @stability    stable
+## @replaceable  no
+## @param        string
+function yetus_error
+{
+  echo "$*" 1>&2
+}
+
+## @description  Print a message to stderr if --debug is turned on
+## @audience     public
+## @stability    stable
+## @replaceable  no
+## @param        string
+function yetus_debug
+{
+  if [[ "${YETUS_SHELL_SCRIPT_DEBUG}" = true ]]; then
+    echo "[$(date) DEBUG]: $*" 1>&2
+  fi
+}
+
+## @description  Given variable $1 delete $2 from it
+## @audience     public
+## @stability    stable
+## @replaceable  no
+function yetus_delete_entry
+{
+  if [[ ${!1} =~ \ ${2}\  ]] ; then
+    yetus_debug "Removing ${2} from ${1}"
+    eval "${1}"=\""${!1// ${2} }"\"
+  fi
+}
+
+## @description  Given variable $1 add $2 to it
+## @audience     public
+## @stability    stable
+## @replaceable  no
+function yetus_add_entry
+{
+  if [[ ! ${!1} =~ \ ${2}\  ]] ; then
+    yetus_debug "Adding ${2} to ${1}"
+    #shellcheck disable=SC2140
+    eval "${1}"=\""${!1} ${2} "\"
+  fi
+}
+
+## @description  Given variable $1 determine if $2 is in it
+## @audience     public
+## @stability    stable
+## @replaceable  no
+## @return       0 = yes, 1 = no
+function yetus_verify_entry
+{
+  [[ ${!1} =~ \ ${2}\  ]]
+}
+
+## @description  run the command, sending stdout and stderr to the given filename
+## @audience     public
+## @stability    stable
+## @param        filename
+## @param        command
+## @param        [..]
+## @replaceable  no
+## @return       $?
+function yetus_run_and_redirect
+{
+  declare logfile=$1
+  shift
+
+  # to the log
+  {
+    date
+    echo "cd $(pwd)"
+    echo "${*}"
+  } >> "${logfile}"
+  # run the actual command
+  "${@}" >> "${logfile}" 2>&1
+}
+
+## @description  Given a filename or dir, return the absolute version of it
+## @audience     public
+## @stability    stable
+## @param        fsobj
+## @replaceable  no
+## @return       0 success
+## @return       1 failure
+## @return       stdout abspath
+function yetus_abs
+{
+  declare obj=$1
+  declare dir
+  declare fn
+
+  if [[ ! -e ${obj} ]]; then
+    return 1
+  elif [[ -d ${obj} ]]; then
+    dir=${obj}
+  else
+    dir=$(dirname -- "${obj}")
+    fn=$(basename -- "${obj}")
+    fn="/${fn}"
+  fi
+
+  dir=$(cd -P -- "${dir}" >/dev/null 2>/dev/null && pwd -P)
+  if [[ $? = 0 ]]; then
+    echo "${dir}${fn}"
+    return 0
+  fi
+  return 1
+}
+
+## @description  Add a header to the usage output
+## @audience     public
+## @stability    evolving
+## @replaceable  no
+## @param        header
+function yetus_add_header
+{
+  declare text=$1
+
+  #shellcheck disable=SC2034
+  YETUS_USAGE_HEADER="${text}"
+}
+
+## @description  Add an option to the usage output
+## @audience     public
+## @stability    evolving
+## @replaceable  no
+## @param        subcommand
+## @param        subcommanddesc
+function yetus_add_option
+{
+  declare option=$1
+  declare text=$2
+
+  YETUS_OPTION_USAGE[${YETUS_OPTION_USAGE_COUNTER}]="${option}@${text}"
+  ((YETUS_OPTION_USAGE_COUNTER=YETUS_OPTION_USAGE_COUNTER+1))
+}
+
+## @description  Reset the usage information to blank
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function yetus_reset_usage
+{
+  # shellcheck disable=SC2034
+  YETUS_OPTION_USAGE=()
+  YETUS_OPTION_USAGE_COUNTER=0
+}
+
+## @description  Print a screen-size aware two-column output
+## @audience     public
+## @stability    evolving
+## @replaceable  no
+## @param        array
+function yetus_generic_columnprinter
+{
+  declare -a input=("$@")
+  declare -i i=0
+  declare -i counter=0
+  declare line
+  declare text
+  declare option
+  declare giventext
+  declare -i maxoptsize
+  declare -i foldsize
+  declare -a tmpa
+  declare numcols
+
+  if [[ -n "${COLUMNS}" ]]; then
+    numcols=${COLUMNS}
+  else
+    numcols=$(tput cols) 2>/dev/null
+  fi
+
+  if [[ -z "${numcols}"
+     || ! "${numcols}" =~ ^[0-9]+$ ]]; then
+    numcols=75
+  else
+    ((numcols=numcols-5))
+  fi
+
+  while read -r line; do
+    tmpa[${counter}]=${line}
+    ((counter=counter+1))
+    option=$(echo "${line}" | cut -f1 -d'@')
+    if [[ ${#option} -gt ${maxoptsize} ]]; then
+      maxoptsize=${#option}
+    fi
+  done < <(for text in "${input[@]}"; do
+    echo "${text}"
+  done | sort)
+
+  i=0
+  ((foldsize=numcols-maxoptsize))
+
+  until [[ $i -eq ${#tmpa[@]} ]]; do
+    option=$(echo "${tmpa[$i]}" | cut -f1 -d'@')
+    giventext=$(echo "${tmpa[$i]}" | cut -f2 -d'@')
+
+    while read -r line; do
+      printf "%-${maxoptsize}s   %-s\n" "${option}" "${line}"
+      option=" "
+    done < <(echo "${giventext}"| fold -s -w ${foldsize})
+    ((i=i+1))
+  done
+}
+
+## @description  Convert a comma-delimited string to an array
+## @audience     public
+## @stability    evolving
+## @replaceable  no
+## @param        arrayname
+## @param        string
+function yetus_comma_to_array
+{
+  declare var=$1
+  declare string=$2
+
+  oldifs="${IFS}"
+  IFS=',' read -r -a "${var}" <<< "${string}"
+  IFS="${oldifs}"
+}
+
+## @description  Check if an array has a given value
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        element
+## @param        array
+## @returns      0 = yes
+## @returns      1 = no
+function yetus_array_contains
+{
+  declare element=$1
+  shift
+  declare val
+
+  if [[ "$#" -eq 0 ]]; then
+    return 1
+  fi
+
+  for val in "${@}"; do
+    if [[ "${val}" == "${element}" ]]; then
+      return 0
+    fi
+  done
+  return 1
+}
+
+## @description  Add the element if it is not
+## @description  present in the given array
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        arrayname
+## @param        element
+function yetus_add_array_element
+{
+  declare arrname=$1
+  declare add=$2
+
+  declare arrref="${arrname}[@]"
+  declare array=("${!arrref}")
+
+  if ! yetus_array_contains "${add}" "${array[@]}"; then
+    # shellcheck disable=SC1083,SC2086
+    eval "${arrname}"=\(\"\${array[@]}\" \"${add}\" \)
+    yetus_debug "$1 accepted $2"
+  else
+    yetus_debug "$1 declined $2"
+  fi
+}
+
+## @description  Sort an array by its elements
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        arrayvar
+function yetus_sort_array
+{
+  declare arrname=$1
+  declare arrref="${arrname}[@]"
+  declare array=("${!arrref}")
+
+  declare globstatus
+  declare oifs
+  declare -a sa
+
+  globstatus=$(set -o | grep noglob | awk '{print $NF}')
+
+  if [[ -n ${IFS} ]]; then
+    oifs=${IFS}
+  fi
+  set -f
+  # shellcheck disable=SC2034
+  IFS=$'\n' sa=($(sort <<<"${array[*]}"))
+  # shellcheck disable=SC1083
+  eval "${arrname}"=\(\"\${sa[@]}\"\)
+
+  if [[ -n "${oifs}" ]]; then
+    IFS=${oifs}
+  else
+    unset IFS
+  fi
+
+  if [[ "${globstatus}" = off ]]; then
+    set +f
+  fi
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/shell/core.d/01-common.sh
----------------------------------------------------------------------
diff --git a/precommit/src/main/shell/core.d/01-common.sh b/precommit/src/main/shell/core.d/01-common.sh
new file mode 100755
index 0000000..0d89106
--- /dev/null
+++ b/precommit/src/main/shell/core.d/01-common.sh
@@ -0,0 +1,643 @@
+#!/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.
+
+## @description  Setup the default global variables
+## @audience     public
+## @stability    stable
+## @replaceable  no
+function common_defaults
+{
+  #shellcheck disable=SC2034
+  BASEDIR=$(pwd)
+  BUGSYSTEMS=""
+  BUILDTOOL="nobuild"
+  BUILDTOOLS=""
+  #shellcheck disable=SC2034
+  EXEC_MODES=""
+  #shellcheck disable=SC2034
+  JENKINS=false
+  LOAD_SYSTEM_PLUGINS=true
+  #shellcheck disable=SC2034
+  OFFLINE=false
+  OSTYPE=$(uname -s)
+  #shellcheck disable=SC2034
+  PATCH_BRANCH=""
+  PATCH_BRANCH_DEFAULT="master"
+  #shellcheck disable=SC2034
+  PATCH_DRYRUNMODE=false
+  PATCH_DIR=/tmp
+  while [[ -e ${PATCH_DIR} ]]; do
+    PATCH_DIR=/tmp/yetus-${RANDOM}.${RANDOM}
+  done
+  #shellcheck disable=SC2034
+  PATCH_METHOD=""
+  #shellcheck disable=SC2034
+  PATCH_METHODS=("gitapply" "patchcmd")
+  #shellcheck disable=SC2034
+  PATCH_LEVEL=0
+  #shellcheck disable=SC2034
+  PATCH_SYSTEM=""
+  PROJECT_NAME=unknown
+  RESULT=0
+  #shellcheck disable=SC2034
+  ROBOT=false
+  #shellcheck disable=SC2034
+  SENTINEL=false
+  #shellcheck disable=SC2034
+  TESTTYPES=""
+  TESTFORMATS=""
+  USER_PLUGIN_DIR=""
+
+  #shellcheck disable=SC2034
+  YETUS_SHELL_SCRIPT_DEBUG=false
+
+  # Solaris needs POSIX and GNU, not SVID
+  case ${OSTYPE} in
+    SunOS)
+      AWK=${AWK:-/usr/xpg4/bin/awk}
+      CURL=${CURL:-curl}
+      DIFF=${DIFF:-/usr/gnu/bin/diff}
+      FILE=${FILE:-file}
+      GIT=${GIT:-git}
+      GREP=${GREP:-/usr/xpg4/bin/grep}
+      PATCH=${PATCH:-/usr/gnu/bin/patch}
+      SED=${SED:-/usr/xpg4/bin/sed}
+    ;;
+    *)
+      AWK=${AWK:-awk}
+      CURL=${CURL:-curl}
+      DIFF=${DIFF:-diff}
+      FILE=${FILE:-file}
+      GIT=${GIT:-git}
+      GREP=${GREP:-grep}
+      PATCH=${PATCH:-patch}
+      SED=${SED:-sed}
+    ;;
+  esac
+
+  RSYNC=${RSYNC:-rsync}
+}
+
+## @description  Interpret the common command line parameters used by test-patch,
+## @description  smart-apply-patch, and the bug system plugins
+## @audience     private
+## @stability    stable
+## @replaceable  no
+## @param        $@
+## @return       May exit on failure
+function common_args
+{
+  declare i
+  declare showhelp=false
+  declare showversion=false
+  declare version
+
+  for i in "$@"; do
+    case ${i} in
+      --awk-cmd=*)
+        AWK=${i#*=}
+      ;;
+      --basedir=*)
+        #shellcheck disable=SC2034
+        BASEDIR=${i#*=}
+      ;;
+      --branch=*)
+        #shellcheck disable=SC2034
+        PATCH_BRANCH=${i#*=}
+      ;;
+      --branch-default=*)
+        #shellcheck disable=SC2034
+        PATCH_BRANCH_DEFAULT=${i#*=}
+      ;;
+      --curl-cmd=*)
+        CURL=${i#*=}
+      ;;
+      --debug)
+        #shellcheck disable=SC2034
+        YETUS_SHELL_SCRIPT_DEBUG=true
+      ;;
+      --diff-cmd=*)
+        DIFF=${i#*=}
+      ;;
+      --file-cmd=*)
+        FILE=${i#*=}
+      ;;
+      --git-cmd=*)
+        GIT=${i#*=}
+      ;;
+      --grep-cmd=*)
+        GREP=${i#*=}
+      ;;
+      --help|-help|-h|help|--h|--\?|-\?|\?)
+        showhelp=true
+      ;;
+      --list-plugins)
+        list_plugins
+        exit 0
+      ;;
+      --offline)
+        #shellcheck disable=SC2034
+        OFFLINE=true
+      ;;
+      --patch-cmd=*)
+        PATCH=${i#*=}
+      ;;
+      --patch-dir=*)
+        PATCH_DIR=${i#*=}
+      ;;
+      --plugins=*)
+        ENABLED_PLUGINS=${i#*=}
+        ENABLED_PLUGINS=${ENABLED_PLUGINS//,/ }
+      ;;
+      --project=*)
+        PROJECT_NAME=${i#*=}
+      ;;
+      --rsync-cmd=*)
+        RSYNC=${i#*=}
+      ;;
+      --skip-system-plugins)
+        LOAD_SYSTEM_PLUGINS=false
+      ;;
+      --sed-cmd=*)
+        SED=${i#*=}
+      ;;
+      --user-plugins=*)
+        USER_PLUGIN_DIR=${i#*=}
+      ;;
+      --version)
+        showversion=true
+      ;;
+      *)
+      ;;
+    esac
+  done
+
+  set_yetus_version
+
+  if [[ ${showhelp} == true ]]; then
+    yetus_usage
+    exit 0
+  fi
+  if [[ ${showversion} == true ]]; then
+    echo "${VERSION}"
+    exit 0
+  fi
+
+  # Absolutely require v1.7.3 or higher
+  # versions lower than this either have bugs with
+  # git apply or don't support all the
+  # expected options
+  version=$(${GIT} --version)
+
+  if [[ $? != 0 ]]; then
+    yetus_error "ERROR: ${GIT} failed during version detection."
+    exit 1
+  fi
+
+  # shellcheck disable=SC2016
+  version=$(echo "${version}" | ${AWK} '{print $NF}')
+  if [[ ${version} =~ ^0
+     || ${version} =~ ^1.[0-6]
+     || ${version} =~ ^1.7.[0-2]$
+    ]]; then
+    yetus_error "ERROR: ${GIT} v1.7.3 or higher is required (found ${version})."
+    exit 1
+  fi
+}
+
+## @description  List all installed plug-ins, regardless of whether
+## @description  they have been enabled
+## @audience     public
+## @stability    evolving
+## @replaceable  no
+function list_plugins
+{
+  declare plugintype
+  declare name
+
+  ENABLED_PLUGINS="all"
+  importplugins
+
+  printf "Reminder: every plug-in may be enabled via 'all'.\n\n"
+  for plugintype in BUILDTOOLS TESTTYPES BUGSYSTEMS TESTFORMATS; do
+    printf "%s:\n\t" ${plugintype}
+    for name in ${!plugintype}; do
+      printf "%s " ${name}
+    done
+    echo ""
+  done
+}
+
+## @description  Let plugins also get a copy of the arguments
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function parse_args_plugins
+{
+  declare plugin
+
+  for plugin in ${TESTTYPES} ${BUGSYSTEMS} ${TESTFORMATS} ${BUILDTOOLS}; do
+    if declare -f ${plugin}_parse_args >/dev/null 2>&1; then
+      yetus_debug "Running ${plugin}_parse_args"
+      #shellcheck disable=SC2086
+      ${plugin}_parse_args "$@"
+      (( RESULT = RESULT + $? ))
+    fi
+  done
+}
+
+## @description  Initialize all enabled plugins
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function plugins_initialize
+{
+  declare plugin
+
+  for plugin in ${TESTTYPES} ${BUGSYSTEMS} ${TESTFORMATS} ${BUILDTOOL}; do
+    if declare -f ${plugin}_initialize >/dev/null 2>&1; then
+      yetus_debug "Running ${plugin}_initialize"
+      #shellcheck disable=SC2086
+      ${plugin}_initialize
+      (( RESULT = RESULT + $? ))
+    fi
+  done
+}
+
+## @description  Determine if a plugin was enabled by the user
+## @description  ENABLED_PLUGINS must be defined
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        test
+function verify_plugin_enabled
+{
+  declare toadd=$1
+  declare bar
+  declare idx
+  declare strip
+  declare stridx
+
+  yetus_debug "Testing if $1 has been enabled by user"
+
+  bar=""
+  for idx in ${ENABLED_PLUGINS}; do
+    stridx=${idx// }
+    yetus_debug "verify_plugin_enabled: processing ${stridx}"
+    case ${stridx} in
+      all)
+        bar=${toadd}
+      ;;
+      -*)
+        strip=${stridx#-}
+        if [[ ${strip} = "${toadd}" ]]; then
+          bar=""
+        fi
+        ;;
+      +*|*)
+        strip=${stridx#+}
+        if [[ ${strip} = "${toadd}" ]]; then
+          bar=${toadd}
+        fi
+      ;;
+    esac
+  done
+
+  if [[ -n ${bar} ]]; then
+    yetus_debug "Post-parsing: checking ${bar} = ${toadd}"
+  fi
+  [[ ${bar} = "${toadd}" ]]
+}
+
+## @description  Personality-defined plug-in list
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        plug-in list string
+function personality_plugins
+{
+  if [[ -z "${ENABLED_PLUGINS}" ]]; then
+    ENABLED_PLUGINS="$1"
+    ENABLED_PLUGINS=${ENABLED_PLUGINS//,/ }
+    yetus_debug "Using personality plug-in list: ${ENABLED_PLUGINS}"
+  fi
+}
+
+## @description  Add the given test type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        test
+function add_test
+{
+  if verify_plugin_enabled "${1}"; then
+    yetus_add_entry NEEDED_TESTS "${1}"
+  fi
+}
+
+## @description  Remove the given test type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        test
+function delete_test
+{
+  yetus_delete_entry NEEDED_TESTS "${1}"
+}
+
+## @description  Verify if a given test was requested
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        test
+## @return       0 = yes
+## @return       1 = no
+function verify_needed_test
+{
+  yetus_verify_entry NEEDED_TESTS "${1}"
+}
+
+## @description  Add the given test type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        plugin
+function add_test_type
+{
+  if verify_plugin_enabled "${1}"; then
+    yetus_add_entry TESTTYPES "${1}"
+  fi
+}
+
+## @description  Remove the given test type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        plugin
+function delete_test_type
+{
+  yetus_delete_entry TESTTYPES "${1}"
+}
+
+## @description  Add the given bugsystem type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        bugsystem
+function add_bugsystem
+{
+  if verify_plugin_enabled "${1}"; then
+    yetus_add_entry BUGSYSTEMS "${1}"
+  fi
+}
+
+## @description  Remove the given bugsystem type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        bugsystem
+function delete_bugsystem
+{
+  yetus_delete_entry BUGSYSTEMS "${1}"
+}
+
+## @description  Add the given test format type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        test format
+function add_test_format
+{
+  if verify_plugin_enabled "${1}"; then
+    yetus_add_entry TESTFORMATS "${1}"
+  fi
+}
+
+## @description  Remove the given test format type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        test format
+function delete_test_format
+{
+  yetus_delete_entry TESTFORMATS "${1}"
+}
+
+## @description  Add the given build tool type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        build tool
+function add_build_tool
+{
+  if verify_plugin_enabled "${1}"; then
+    yetus_add_entry BUILDTOOLS "${1}"
+  fi
+}
+
+## @description  Remove the given build tool type
+## @audience     public
+## @stability    stable
+## @replaceable  yes
+## @param        build tool
+function delete_build_tool
+{
+  yetus_delete_entry BUILDTOOLS "${1}"
+}
+
+## @description  Import content from test-patch.d and optionally
+## @description  from user provided plugin directory
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function importplugins
+{
+  local i
+  local plugin
+  local files=()
+
+  if [[ ${LOAD_SYSTEM_PLUGINS} == "true" ]]; then
+    if [[ -d "${BINDIR}/test-patch.d" ]]; then
+      files=(${BINDIR}/test-patch.d/*.sh)
+    fi
+  fi
+
+  if [[ -n "${USER_PLUGIN_DIR}" && -d "${USER_PLUGIN_DIR}" ]]; then
+    yetus_debug "Loading user provided plugins from ${USER_PLUGIN_DIR}"
+    files=("${files[@]}" ${USER_PLUGIN_DIR}/*.sh)
+  fi
+
+  if [[ -n ${PERSONALITY} && ! -f ${PERSONALITY} ]]; then
+    yetus_error "ERROR: Can't find ${PERSONALITY} to import."
+    unset PERSONALITY
+  fi
+
+  if [[ -z ${PERSONALITY}
+      && -f "${BINDIR}/personality/${PROJECT_NAME}.sh"
+      && ${LOAD_SYSTEM_PLUGINS} = "true" ]]; then
+    yetus_debug "Using project personality."
+    PERSONALITY="${BINDIR}/personality/${PROJECT_NAME}.sh"
+  fi
+
+  if [[ -n ${PERSONALITY} && -f ${PERSONALITY} ]]; then
+    yetus_debug "Importing ${PERSONALITY}"
+    # shellcheck disable=SC1090
+    . "${PERSONALITY}"
+  fi
+
+  for i in "${files[@]}"; do
+    if [[ -f ${i} ]]; then
+      yetus_debug "Importing ${i}"
+      #shellcheck disable=SC1090
+      . "${i}"
+    fi
+  done
+
+  if declare -f personality_globals > /dev/null; then
+    personality_globals
+  fi
+}
+
+## @description  Print the plugin's usage info
+## @audience     public
+## @stability    evolving
+## @replaceable  no
+## @param        array
+function plugin_usage_output
+{
+  echo ""
+  echo "${YETUS_USAGE_HEADER}"
+  echo ""
+}
+
+## @description  Verifies the existence of a command
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        commandname
+## @param        commandpath
+## @return       0 = ok
+## @return       1 = error
+function verify_command
+{
+  local cmd_name="$1"
+  local cmd_path="$2"
+
+  if [[ -z ${cmd_path} ]]; then
+    yetus_error "executable for '${cmd_name}' was not specified."
+    return 1
+  fi
+  if [[ ! "${cmd_path}" =~ / ]]; then
+    cmd_path=$(command -v "${cmd_path}")
+  fi
+  if [[ ! -f ${cmd_path} ]]; then
+    yetus_error "executable '${cmd_path}' for '${cmd_name}' does not exist."
+    return 1
+  fi
+  if [[ ! -x ${cmd_path} ]]; then
+    yetus_error "executable '${cmd_path}' for '${cmd_name}' is not executable."
+    return 1
+  fi
+  return 0
+}
+
+## @description  Faster dirname, given the assumption that
+## @description  dirs are always absolute (e.g., start with /)
+## @description  DO NOT USE with relative paths or where
+## @description  assumption may not be valid!
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        fileobj
+function faster_dirname
+{
+  declare o=$1
+
+  if [[ "${o}" =~ / ]]; then
+    echo "${o%/*}"
+  else
+    echo .
+  fi
+}
+
+## @description  Set the USER_NAME, USER_ID, and GROUP_ID env vars
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function determine_user
+{
+  # On the Apache Jenkins hosts, $USER is pretty much untrustable because
+  # something sets it to an account that doesn't actually exist.
+  # Instead, we need to try and override it with something that's
+  # probably close to reality.
+  if [[ ${TESTPATCHMODE} =~ jenkins ]]; then
+    USER=$(id | cut -f2 -d\( | cut -f1 -d\))
+  fi
+
+  USER_NAME=${SUDO_USER:=$USER}
+  # shellcheck disable=SC2034
+  USER_ID=$(id -u "${USER_NAME}")
+  # shellcheck disable=SC2034
+  GROUP_ID=$(id -g "${USER_NAME}")
+}
+
+## @description  Kill a process id
+## @audience     private
+## @stability    evolving
+## @replaceable  yes
+## @param        pid
+function pid_kill
+{
+  declare pid=$1
+  declare cmd
+  declare kill_timeout=3
+
+  kill "${pid}" >/dev/null 2>&1
+  sleep "${kill_timeout}"
+  if kill -0 "${pid}" > /dev/null 2>&1; then
+    yetus_error "WARNING: ${pid} did not stop gracefully after ${kill_timeout} second(s): Trying to kill with kill -9"
+    kill -9 "${pid}" >/dev/null 2>&1
+  fi
+  if ps -p "${pid}" > /dev/null 2>&1; then
+    cmd=$(ps -o args "${pid}")
+    yetus_error "ERROR: Unable to kill ${pid}: ${cmd}"
+  fi
+}
+
+## @description  set VERSION to the current version if not set
+## @audience     private
+## @stability    evolving
+## @replaceable  yes
+function set_yetus_version
+{
+
+  if [[ -n "${VERSION}" ]]; then
+    return
+  fi
+
+  if [[ -f "${BINDIR}/../VERSION" ]]; then
+    # old src version file
+    VERSION=$(cat "${BINDIR}/../VERSION")
+  elif [[ -f "${BINDIR}/VERSION" ]]; then
+    # dist version file
+    VERSION=$(cat "${BINDIR}/VERSION")
+  elif [[ -f "${BINDIR}/../../../pom.xml" ]]; then
+    # this way we have no dependency on Maven being installed
+    VERSION=$(${GREP} "<version>" "${BINDIR}/../../../pom.xml" 2>/dev/null \
+      | head -1 \
+      | ${SED}  -e 's|^ *<version>||' -e 's|</version>.*$||' 2>/dev/null)
+  fi
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/shell/core.d/builtin-bugsystem.sh
----------------------------------------------------------------------
diff --git a/precommit/src/main/shell/core.d/builtin-bugsystem.sh b/precommit/src/main/shell/core.d/builtin-bugsystem.sh
new file mode 100755
index 0000000..0aeddf1
--- /dev/null
+++ b/precommit/src/main/shell/core.d/builtin-bugsystem.sh
@@ -0,0 +1,185 @@
+#!/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 the output on the screen.
+
+add_bugsystem console
+
+CONSOLE_USE_BUILD_URL=false
+
+## @description  Print out the finished details on the console
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        runresult
+## @return       0 on success
+## @return       1 on failure
+function console_finalreport
+{
+  declare result=$1
+  shift
+  declare i=0
+  declare ourstring
+  declare vote
+  declare subs
+  declare ela
+  declare comment
+  declare commentfile1="${PATCH_DIR}/comment.1"
+  declare commentfile2="${PATCH_DIR}/comment.2"
+  declare normaltop
+  declare line
+  declare seccoladj=0
+  declare spcfx=${PATCH_DIR}/spcl.txt
+  declare calctime
+
+  if [[ -n "${CONSOLE_REPORT_FILE}" ]]; then
+    exec 6>&1
+    exec >"${CONSOLE_REPORT_FILE}"
+  fi
+
+  if [[ ${result} == 0 ]]; then
+    if [[ ${ROBOT} == false ]]; then
+      if declare -f ${PROJECT_NAME}_console_success >/dev/null; then
+        "${PROJECT_NAME}_console_success" > "${spcfx}"
+      else
+        {
+          printf "IF9fX18gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBfIAovIF9fX3wg";
+          printf "XyAgIF8gIF9fXyBfX18gX19fICBfX18gX19ffCB8ClxfX18gXHwgfCB8IHwv";
+          printf "IF9fLyBfXy8gXyBcLyBfXy8gX198IHwKIF9fXykgfCB8X3wgfCAoX3wgKF98";
+          printf "ICBfXy9cX18gXF9fIFxffAp8X19fXy8gXF9fLF98XF9fX1xfX19cX19ffHxf";
+          printf "X18vX19fKF8pCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg";
+          printf "ICAK";
+        } > "${spcfx}"
+      fi
+    fi
+    printf "\n\n+1 overall\n\n"
+  else
+    if [[ ${ROBOT} == false ]]; then
+      if declare -f ${PROJECT_NAME}_console_failure >/dev/null; then
+        "${PROJECT_NAME}_console_failure" > "${spcfx}"
+      else
+        {
+          printf "IF9fX19fICAgICBfIF8gICAgICAgICAgICAgICAgXyAKfCAgX19ffF8gXyhf";
+          printf "KSB8XyAgIF8gXyBfXyBfX198IHwKfCB8XyAvIF9gIHwgfCB8IHwgfCB8ICdf";
+          printf "Xy8gXyBcIHwKfCAgX3wgKF98IHwgfCB8IHxffCB8IHwgfCAgX18vX3wKfF98";
+          printf "ICBcX18sX3xffF98XF9fLF98X3wgIFxfX18oXykKICAgICAgICAgICAgICAg";
+          printf "ICAgICAgICAgICAgICAgICAK"
+        } > "${spcfx}"
+      fi
+    fi
+    printf "\n\n-1 overall\n\n"
+  fi
+
+  if [[ -f ${spcfx} ]]; then
+    if which base64 >/dev/null 2>&1; then
+      base64 --decode "${spcfx}" 2>/dev/null
+    elif which openssl >/dev/null 2>&1; then
+      openssl enc -A -d -base64 -in "${spcfx}" 2>/dev/null
+    fi
+    echo
+    echo
+    rm "${spcfx}"
+  fi
+
+  seccoladj=$(findlargest 2 "${TP_VOTE_TABLE[@]}")
+  if [[ ${seccoladj} -lt 10 ]]; then
+    seccoladj=10
+  fi
+
+  seccoladj=$((seccoladj + 2 ))
+  i=0
+  until [[ $i -eq ${#TP_HEADER[@]} ]]; do
+    printf "%s\n" "${TP_HEADER[${i}]}"
+    ((i=i+1))
+  done
+
+  printf "| %s | %*s |  %s   | %s\n" "Vote" ${seccoladj} Subsystem Runtime "Comment"
+  echo "============================================================================"
+  i=0
+  until [[ $i -eq ${#TP_VOTE_TABLE[@]} ]]; do
+    ourstring=$(echo "${TP_VOTE_TABLE[${i}]}" | tr -s ' ')
+    vote=$(echo "${ourstring}" | cut -f2 -d\|)
+    subs=$(echo "${ourstring}"  | cut -f3 -d\|)
+    ela=$(echo "${ourstring}" | cut -f4 -d\|)
+    calctime=$(clock_display "${ela}")
+    comment=$(echo "${ourstring}"  | cut -f5 -d\|)
+
+    echo "${comment}" | fold -s -w $((78-seccoladj-22)) > "${commentfile1}"
+    normaltop=$(head -1 "${commentfile1}")
+    ${SED} -e '1d' "${commentfile1}"  > "${commentfile2}"
+
+    if [[ "${vote}" = "H" ]]; then
+      printf "|      | %*s |            |%-s\n" ${seccoladj} " " "${normaltop}"
+    else
+      printf "| %4s | %*s | %-10s |%-s\n" "${vote}" ${seccoladj} \
+        "${subs}" "${calctime}" "${normaltop}"
+    fi
+    while read -r line; do
+      printf "|      | %*s |            | %-s\n" ${seccoladj} " " "${line}"
+    done < "${commentfile2}"
+
+    ((i=i+1))
+    rm "${commentfile2}" "${commentfile1}" 2>/dev/null
+  done
+
+  if [[ ${#TP_TEST_TABLE[@]} -gt 0 ]]; then
+    seccoladj=$(findlargest 1 "${TP_TEST_TABLE[@]}")
+    printf "\n\n%*s | Tests\n" "${seccoladj}" "Reason"
+    i=0
+    until [[ $i -eq ${#TP_TEST_TABLE[@]} ]]; do
+      ourstring=$(echo "${TP_TEST_TABLE[${i}]}" | tr -s ' ')
+      vote=$(echo "${ourstring}" | cut -f2 -d\|)
+      subs=$(echo "${ourstring}"  | cut -f3 -d\|)
+      printf "%*s | %s\n" "${seccoladj}" "${vote}" "${subs}"
+      ((i=i+1))
+    done
+  fi
+
+  printf "\n\n|| Subsystem || Report/Notes ||\n"
+  echo "============================================================================"
+  i=0
+
+  until [[ $i -eq ${#TP_FOOTER_TABLE[@]} ]]; do
+    if [[ "${CONSOLE_USE_BUILD_URL}" = true &&
+          -n "${BUILD_URL}" ]]; then
+      comment=$(echo "${TP_FOOTER_TABLE[${i}]}" |
+                ${SED} -e "s,@@BASE@@,${BUILD_URL}${BUILD_URL_ARTIFACTS},g")
+    else
+      comment=$(echo "${TP_FOOTER_TABLE[${i}]}" |
+                ${SED} -e "s,@@BASE@@,${PATCH_DIR},g")
+    fi
+    printf "%s\n" "${comment}"
+    ((i=i+1))
+  done
+
+  if [[ -n "${CONSOLE_REPORT_FILE}" ]]; then
+    exec 1>&6 6>&-
+    cat "${CONSOLE_REPORT_FILE}"
+  fi
+}
+
+
+## @description  Give access to the brief report file in docker mode
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function console_docker_support
+{
+  if [[ -n "${CONSOLE_REPORT_FILE}" ]]; then
+    DOCKER_EXTRAARGS+=("-v" "${CONSOLE_REPORT_FILE}:/testptch/console.txt")
+  fi
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/shell/core.d/builtin-personality.sh
----------------------------------------------------------------------
diff --git a/precommit/src/main/shell/core.d/builtin-personality.sh b/precommit/src/main/shell/core.d/builtin-personality.sh
new file mode 100755
index 0000000..c473d66
--- /dev/null
+++ b/precommit/src/main/shell/core.d/builtin-personality.sh
@@ -0,0 +1,39 @@
+#!/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.
+
+## @description  Generate a list of all personality modules for a given
+## @description  buildtool for the system to invoke
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function personality_modules
+{
+  if declare -f "${BUILDTOOL}_builtin_personality_modules" >/dev/null; then
+    "${BUILDTOOL}_builtin_personality_modules" "$@"
+  fi
+}
+
+## @description  Generate a list of all personality file tests for a given
+## @description  buildtool for the system to invoke
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function personality_file_tests
+{
+  if declare -f "${BUILDTOOL}_builtin_personality_file_tests" >/dev/null; then
+    "${BUILDTOOL}_builtin_personality_file_tests" "$@"
+  fi
+}

http://git-wip-us.apache.org/repos/asf/yetus/blob/6ebaa111/precommit/src/main/shell/core.d/docker.sh
----------------------------------------------------------------------
diff --git a/precommit/src/main/shell/core.d/docker.sh b/precommit/src/main/shell/core.d/docker.sh
new file mode 100755
index 0000000..83efc3b
--- /dev/null
+++ b/precommit/src/main/shell/core.d/docker.sh
@@ -0,0 +1,661 @@
+#!/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.
+
+DOCKERMODE=false
+DOCKERCMD=$(command -v docker)
+DOCKER_ID=${RANDOM}
+DOCKER_DESTRUCTIVE=true
+DOCKERFILE_DEFAULT="${BINDIR}/test-patch-docker/Dockerfile"
+DOCKERFAIL="fallback,continue,fail"
+DOCKERSUPPORT=false
+DOCKER_ENABLE_PRIVILEGED=true
+DOCKER_CLEANUP_CMD=false
+DOCKER_MEMORY="4g"
+
+declare -a DOCKER_EXTRAARGS
+
+####
+#### IMPORTANT
+####
+#### If these times are updated, the documentation needs to
+#### be changed too!
+
+# created, stopped, exited, running, for 24 hours
+DOCKER_CONTAINER_PURGE=("86400" "86400" "86400" "86400" )
+
+# keep images for 1 week
+DOCKER_IMAGE_PURGE=604800
+
+## @description  Docker-specific usage
+## @stability    stable
+## @audience     private
+## @replaceable  no
+function docker_usage
+{
+  if [[ "${DOCKER_CLEANUP_CMD}" == false ]]; then
+    yetus_add_option "--docker" "Spawn a docker container"
+  fi
+  yetus_add_option "--dockercmd=<file>" "Command to use as docker executable (default: '${DOCKERCMD}')"
+  if [[ "${DOCKER_CLEANUP_CMD}" == false ]]; then
+    yetus_add_option "--dockerfile=<file>" "Dockerfile fragment to use as the base (default: '${DOCKERFILE_DEFAULT}')"
+    yetus_add_option "--dockeronfail=<list>" "If Docker fails, determine fallback method order (default: ${DOCKERFAIL})"
+    yetus_add_option "--dockerprivd=<bool>" "Run docker in privileged mode (default: '${DOCKER_ENABLE_PRIVILEGED}')"
+  fi
+  yetus_add_option "--dockerdelrep" "In Docker mode, only report image/container deletions, not act on them"
+  if [[ "${DOCKER_CLEANUP_CMD}" == false ]]; then
+    yetus_add_option "--dockermemlimit=<num>" "Limit a Docker container's memory usage (default: ${DOCKER_MEMORY})"
+  fi
+}
+
+## @description  Docker-specific argument parsing
+## @stability    stable
+## @audience     private
+## @replaceable  no
+## @params       arguments
+function docker_parse_args
+{
+  declare i
+
+  for i in "$@"; do
+    case ${i} in
+      --docker)
+        DOCKERSUPPORT=true
+      ;;
+      --dockercmd=*)
+        #shellcheck disable=SC2034
+        DOCKERCMD=${i#*=}
+      ;;
+      --dockerdelrep)
+        DOCKER_DESTRUCTIVE=false
+      ;;
+      --dockerfile=*)
+        DOCKERFILE=${i#*=}
+      ;;
+      --dockermemlimit=*)
+        DOCKER_MEMORY=${i#*=}
+      ;;
+      --dockermode)
+        DOCKERMODE=true
+      ;;
+      --dockeronfail=*)
+        DOCKERFAIL=${i#*=}
+      ;;
+      --dockerprivd=*)
+        DOCKER_ENABLE_PRIVILEGED=${i#*=}
+      ;;
+    esac
+  done
+}
+
+## @description  Docker initialization pre- and post- re-exec
+## @stability    stable
+## @audience     private
+## @replaceable  no
+function docker_initialize
+{
+  declare dockvers
+
+  # --docker and --dockermode are mutually
+  # exclusive.  --docker is used by the user to
+  # re-exec test-patch in Docker mode.
+  # --dockermode is used by launch-test-patch (which is
+  # run as the Docker EXEC in the Dockerfile,
+  # see elsewhere for more info) to tell test-patch that
+  # it has been restarted already. launch-test-patch
+  # also strips --docker from the command line so that we
+  # don't end up in a loop if the docker image
+  # also has the docker command in it
+
+  # we are already in docker mode
+  if [[ "${DOCKERMODE}" == true ]]; then
+    # DOCKER_VERSION is set by our creator.
+    add_footer_table "Docker" "${DOCKER_VERSION}"
+    return
+  fi
+
+  # docker mode hasn't been requested
+  if [[ "${DOCKERSUPPORT}" != true ]]; then
+    return
+  fi
+
+  # turn DOCKERFAIL into a string composed of numbers
+  # to ease interpretation:  123, 213, 321, ... whatever
+  # some of these combos are non-sensical but that's ok.
+  # we'll treat non-sense as effectively errors.
+  DOCKERFAIL=${DOCKERFAIL//,/ }
+  DOCKERFAIL=${DOCKERFAIL//fallback/1}
+  DOCKERFAIL=${DOCKERFAIL//continue/2}
+  DOCKERFAIL=${DOCKERFAIL//fail/3}
+  DOCKERFAIL=${DOCKERFAIL//[[:blank:]]/}
+
+  if ! docker_exeverify; then
+    if [[ "${DOCKERFAIL}" =~ ^12
+       || "${DOCKERFAIL}" =~ ^2 ]]; then
+      add_vote_table 0 docker "Docker command '${DOCKERCMD}' not found/broken. Disabling docker."
+      DOCKERSUPPORT=false
+    else
+      add_vote_table -1 docker "Docker command '${DOCKERCMD}' not found/broken."
+      bugsystem_finalreport 1
+      cleanup_and_exit 1
+    fi
+  fi
+
+  dockvers=$(docker_version Client)
+  if [[ "${dockvers}" =~ ^0
+     || "${dockvers}" =~ ^1\.[0-5]$ || "${dockvers}" =~ ^1\.[0-5]\. ]]; then
+    if [[ "${DOCKERFAIL}" =~ ^12
+       || "${DOCKERFAIL}" =~ ^2 ]]; then
+      add_vote_table 0 docker "Docker command '${DOCKERCMD}' is too old (${dockvers} < 1.6.0). Disabling docker."
+      DOCKERSUPPORT=false
+    else
+      add_vote_table -1 docker "Docker command '${DOCKERCMD}' is too old (${dockvers} < 1.6.0). Disabling docker."
+      bugsystem_finalreport 1
+      cleanup_and_exit 1
+    fi
+  fi
+}
+
+## @description  Verify dockerfile exists
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       exits on failure if configured
+function docker_fileverify
+{
+  if [[ ${DOCKERMODE} = false &&
+        ${DOCKERSUPPORT} = true ]]; then
+    if [[ -n "${DOCKERFILE}" ]]; then
+      pushd "${STARTINGDIR}" >/dev/null
+      if [[ -f ${DOCKERFILE} ]]; then
+        DOCKERFILE=$(yetus_abs "${DOCKERFILE}")
+      else
+        if [[ "${DOCKERFAIL}" =~ ^1 ]]; then
+          yetus_error "ERROR: Dockerfile '${DOCKERFILE}' not found, falling back to built-in."
+          add_vote_table 0 docker "Dockerfile '${DOCKERFILE}' not found, falling back to built-in."
+          DOCKERFILE=${DOCKERFILE_DEFAULT}
+        elif [[ "${DOCKERFAIL}" =~ ^2 ]]; then
+          yetus_error "ERROR: Dockerfile '${DOCKERFILE}' not found, disabling docker."
+          add_vote_table 0 docker "Dockerfile '${DOCKERFILE}' not found, disabling docker."
+          DOCKERSUPPORT=false
+        else
+          yetus_error "ERROR: Dockerfile '${DOCKERFILE}' not found."
+          add_vote_table -1 docker "Dockerfile '${DOCKERFILE}' not found."
+          bugsystem_finalreport 1
+          cleanup_and_exit 1
+        fi
+      fi
+      popd >/dev/null
+    else
+      DOCKERFILE=${DOCKERFILE_DEFAULT}
+    fi
+  fi
+}
+
+## @description  Verify docker exists
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       1 if docker is broken
+## @return       0 if docker is working
+function docker_exeverify
+{
+  if ! verify_command "Docker" "${DOCKERCMD}"; then
+    return 1
+  fi
+
+  if ! ${DOCKERCMD} info >/dev/null 2>&1; then
+    yetus_error "Docker is not functioning properly. Daemon down/unreachable?"
+    return 1
+  fi
+  return 0
+}
+
+## @description  Run docker with some arguments, and
+## @description  optionally send to debug.
+## @description  some destructive commands require
+## @description  DOCKER_DESTRUCTIVE to be set to true
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        args
+function dockercmd
+{
+  declare subcmd=$1
+  shift
+
+  yetus_debug "dockercmd: ${DOCKERCMD} ${subcmd} $*"
+  if [[ ${subcmd} == rm
+      || ${subcmd} == rmi
+      || ${subcmd} == stop
+      || ${subcmd} == kill ]]; then
+    if [[ "${DOCKER_DESTRUCTIVE}" == false ]]; then
+      yetus_error "Safemode: not running ${DOCKERCMD} ${subcmd} $*"
+      return
+    fi
+  fi
+  "${DOCKERCMD}" "${subcmd}" "$@"
+}
+
+## @description  Convet docker's time format to ctime
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        time
+function dockerdate_to_ctime
+{
+  declare mytime=$1
+
+  if [[ "${mytime}" = "0001-01-01T00:00:00Z" ]]; then
+    mytime="1970-01-01T00:00:00"
+  fi
+
+  # believe it or not, date is not even close to standardized...
+  if [[ $(uname -s) == Linux ]]; then
+
+    # GNU date
+    date -d "${mytime}" "+%s"
+  else
+
+    # BSD date; docker gives us two different format because fun
+    if ! date -j -f "%FT%T%z" "${mytime}" "+%s" 2>/dev/null; then
+      date -j -f "%FT%T" "${mytime}" "+%s"
+    fi
+  fi
+}
+
+## @description  Stop and delete all defunct containers
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function docker_container_maintenance
+{
+  declare line
+  declare id
+  declare name
+  declare status
+  declare tmptime
+  declare createtime
+  declare starttime
+  declare stoptime
+  declare remove
+  declare difftime
+  declare data
+
+  if [[ "${ROBOT}" = false ]]; then
+    return
+  fi
+
+  big_console_header "Docker Container Maintenance"
+
+  dockercmd ps -a
+
+  data=$(dockercmd ps -qa)
+
+  if [[ -z "${data}" ]]; then
+    return
+  fi
+
+  while read -r line; do
+    id=$(echo "${line}" | cut -f1 -d, )
+    status=$(echo "${line}" | cut -f2 -d, )
+    tmptime=$(echo "${line}" | cut -f3 -d, | cut -f1 -d. )
+    createtime=$(dockerdate_to_ctime "${tmptime}")
+    tmptime=$(echo "${line}" | cut -f4 -d, | cut -f1 -d. )
+    starttime=$(dockerdate_to_ctime "${tmptime}")
+    tmptime=$(echo "${line}" | cut -f5 -d, | cut -f1 -d. )
+    stoptime=$(dockerdate_to_ctime "${tmptime}")
+    name=$(echo "${line}" | cut -f6 -d, )
+    curtime=$("${AWK}" 'BEGIN {srand(); print srand()}')
+    remove=false
+
+    case ${status} in
+      created)
+        ((difftime = curtime - createtime))
+        if [[ ${difftime} -gt ${DOCKER_CONTAINER_PURGE[0]} ]]; then
+          remove=true
+        fi
+      ;;
+      stopped)
+        ((difftime = curtime - stoptime))
+        if [[ ${difftime} -gt ${DOCKER_CONTAINER_PURGE[1]} ]]; then
+          remove=true
+        fi
+      ;;
+      exited | dead)
+        ((difftime = curtime - stoptime))
+        if [[ ${difftime} -gt ${DOCKER_CONTAINER_PURGE[2]} ]]; then
+          remove=true
+        fi
+      ;;
+      running)
+        ((difftime = curtime - starttime))
+        if [[ ${difftime} -gt ${DOCKER_CONTAINER_PURGE[3]}
+             && "${SENTINEL}" = true ]]; then
+          remove=true
+          echo "Attempting to kill docker container ${name} [${id}]"
+          dockercmd kill "${id}"
+        fi
+      ;;
+      *)
+      ;;
+    esac
+
+    if [[ "${remove}" == true ]]; then
+      echo "Attempting to remove docker container ${name} [${id}]"
+      dockercmd rm "${id}"
+    fi
+
+  done < <(
+     # shellcheck disable=SC2086
+     dockercmd inspect \
+        --format '{{.Id}},{{.State.Status}},{{.Created}},{{.State.StartedAt}},{{.State.FinishedAt}},{{.Name}}' \
+       ${data})
+}
+
+## @description  Delete images after ${DOCKER_IMAGE_PURGE}
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function docker_image_maintenance_helper
+{
+  declare id
+  declare tmptime
+  declare createtime
+  declare difftime
+  declare name
+
+  if [[ "${ROBOT}" = false ]]; then
+    return
+  fi
+
+  if [[ -z "$*" ]]; then
+    return
+  fi
+
+  for id in "$@"; do
+    tmptime=$(dockercmd inspect --format '{{.Created}}' "${id}" | cut -f1 -d. )
+    createtime=$(dockerdate_to_ctime "${tmptime}")
+    curtime=$(date "+%s")
+
+    ((difftime = curtime - createtime))
+    if [[ ${difftime} -gt ${DOCKER_IMAGE_PURGE} ]]; then
+      echo "Attempting to remove docker image ${id}"
+      dockercmd rmi "${id}"
+    fi
+  done
+}
+
+
+## @description  get sentinel-level docker images
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        args
+function docker_get_sentinel_images
+{
+  #shellcheck disable=SC2016
+  dockercmd images \
+    | tail -n +2 \
+    | "${GREP}" -v hours \
+    | "${AWK}" '{print $1":"$2}' \
+    | "${GREP}" -v "<none>:<none>"
+}
+
+## @description  Remove untagged/unused images
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        args
+function docker_image_maintenance
+{
+  declare id
+
+  if [[ "${ROBOT}" = false ]]; then
+    return
+  fi
+
+  big_console_header "Removing old images"
+
+  dockercmd images
+
+  echo "Untagged images:"
+
+  #shellcheck disable=SC2046
+  docker_image_maintenance_helper $(dockercmd images --filter "dangling=true" -q --no-trunc)
+
+  echo "Apache Yetus images:"
+
+  # removing this by image id doesn't always work without a force
+  # in the situations that, for whatever reason, docker decided
+  # to use the same image. this was a rare problem with older
+  # releases of yetus. at some point, we should revisit this
+  # in the mean time, we're going to reconstruct the
+  # repostory:tag and send that to get removed.
+
+  #shellcheck disable=SC2046,SC2016
+  docker_image_maintenance_helper $(dockercmd images | ${GREP} -e ^yetus | grep tp- | ${AWK} '{print $1":"$2}')
+  #shellcheck disable=SC2046,SC2016
+  docker_image_maintenance_helper $(dockercmd images | ${GREP} -e ^yetus | ${GREP} -v hours | ${AWK} '{print $1":"$2}')
+
+  if [[ "${SENTINEL}" = false ]]; then
+    return
+  fi
+
+  echo "Other images:"
+  #shellcheck disable=SC2046
+  docker_image_maintenance_helper $(docker_get_sentinel_images)
+}
+
+
+## @description  Perform pre-run maintenance to free up
+## @description  resources. With --jenkins, it is a lot
+## @description  more destructive.
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        args
+function docker_cleanup
+{
+
+  docker_image_maintenance
+
+  docker_container_maintenance
+}
+
+## @description  Determine the revision of a dockerfile
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        args
+function docker_getfilerev
+{
+  ${GREP} 'YETUS_PRIVATE: gitrev=' \
+        "${PATCH_DIR}/precommit/test-patch-docker/Dockerfile" \
+          | cut -f2 -d=
+}
+
+function docker_version
+{
+  declare vertype=$1
+  declare val
+  declare ret
+
+  # new version command
+  val=$(dockercmd version --format "{{.${vertype}.Version}}" 2>/dev/null)
+  ret=$?
+
+  if [[ ${ret} != 0 ]];then
+    # old version command
+    val=$(dockercmd version | ${GREP} "${vertype} version" | cut -f2 -d: | tr -d ' ')
+  fi
+
+  echo "${val}"
+}
+
+## @description  Start a test patch docker container
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        args
+function docker_run_image
+{
+  declare dockerfilerev
+  declare baseimagename
+  declare patchimagename="yetus/${PROJECT_NAME}:tp-${DOCKER_ID}"
+  declare containername="yetus_tp-${DOCKER_ID}"
+  declare client
+  declare server
+  declare retval
+  declare elapsed
+
+  dockerfilerev=$(docker_getfilerev)
+
+  baseimagename="yetus/${PROJECT_NAME}:${dockerfilerev}"
+
+  # make a base image, if it isn't available
+  big_console_header "Building base image: ${baseimagename}"
+  start_clock
+  dockercmd build \
+    -t "${baseimagename}" \
+    "${PATCH_DIR}/precommit/test-patch-docker"
+  retval=$?
+
+  #shellcheck disable=SC2046
+  elapsed=$(clock_display $(stop_clock))
+
+  echo ""
+  echo "Total Elapsed time: ${elapsed}"
+  echo ""
+
+  if [[ ${retval} != 0 ]]; then
+    yetus_error "ERROR: Docker failed to build image."
+    add_vote_table -1 docker "Docker failed to build ${baseimagename}."
+    bugsystem_finalreport 1
+    cleanup_and_exit 1
+  fi
+
+  big_console_header "Building ${BUILDMODE} image: ${patchimagename}"
+  start_clock
+  # using the base image, make one that is patch specific
+  dockercmd build \
+    -t "${patchimagename}" \
+    - <<PatchSpecificDocker
+FROM ${baseimagename}
+LABEL org.apache.yetus=""
+LABEL org.apache.yetus.testpatch.patch="tp-${DOCKER_ID}"
+LABEL org.apache.yetus.testpatch.project=${PROJECT_NAME}
+RUN groupadd --non-unique -g ${GROUP_ID} ${USER_NAME} || true
+RUN useradd -g ${GROUP_ID} -u ${USER_ID} -m ${USER_NAME} || true
+RUN chown -R ${USER_NAME} /home/${USER_NAME} || true
+ENV HOME /home/${USER_NAME}
+USER ${USER_NAME}
+PatchSpecificDocker
+
+  retval=$?
+
+  #shellcheck disable=SC2046
+  elapsed=$(clock_display $(stop_clock))
+
+  echo ""
+  echo "Total Elapsed time: ${elapsed}"
+  echo ""
+
+  if [[ ${retval} != 0 ]]; then
+    yetus_error "ERROR: Docker failed to build image."
+    add_vote_table -1 docker "Docker failed to build ${patchimagename}."
+    bugsystem_finalreport 1
+    cleanup_and_exit 1
+  fi
+
+  if [[ "${DOCKER_ENABLE_PRIVILEGED}" = true ]]; then
+    DOCKER_EXTRAARGS+=("--privileged")
+  fi
+
+  if [[ -n "${DOCKER_MEMORY}" ]]; then
+    DOCKER_EXTRAARGS+=("-m" "${DOCKER_MEMORY}")
+  fi
+
+  client=$(docker_version Client)
+  server=$(docker_version Server)
+
+  dockerversion="Client=${client} Server=${server}"
+
+
+  # make the kernel prefer to kill us if we run out of RAM
+  DOCKER_EXTRAARGS+=("--oom-score-adj" "500")
+
+  DOCKER_EXTRAARGS+=("--cidfile=${PATCH_DIR}/cidfile")
+  DOCKER_EXTRAARGS+=(-v "${PWD}:/testptch/${PROJECT_NAME}")
+  DOCKER_EXTRAARGS+=(-u "${USER_NAME}")
+  DOCKER_EXTRAARGS+=(-w "/testptch/${PROJECT_NAME}")
+  DOCKER_EXTRAARGS+=("--env=BASEDIR=/testptch/${PROJECT_NAME}")
+  DOCKER_EXTRAARGS+=("--env=DOCKER_VERSION=${dockerversion} Image:${baseimagename}")
+  DOCKER_EXTRAARGS+=("--env=JAVA_HOME=${JAVA_HOME}")
+  DOCKER_EXTRAARGS+=("--env=PATCH_SYSTEM=${PATCH_SYSTEM}")
+  DOCKER_EXTRAARGS+=("--env=PROJECT_NAME=${PROJECT_NAME}")
+  DOCKER_EXTRAARGS+=("--env=TESTPATCHMODE=${TESTPATCHMODE}")
+  DOCKER_EXTRAARGS+=(--name "${containername}")
+
+
+  trap 'docker_signal_handler' SIGTERM
+  trap 'docker_signal_handler' SIGINT
+
+  if [[ ${PATCH_DIR} =~ ^/ ]]; then
+    dockercmd run --rm=true -i \
+      "${DOCKER_EXTRAARGS[@]}" \
+      -v "${PATCH_DIR}:/testptch/patchprocess" \
+      --env=PATCH_DIR=/testptch/patchprocess \
+      "${patchimagename}" &
+  else
+    dockercmd run --rm=true -i \
+      "${DOCKER_EXTRAARGS[@]}" \
+      --env=PATCH_DIR="${PATCH_DIR}" \
+      "${patchimagename}" &
+  fi
+
+  wait ${!}
+  cleanup_and_exit $?
+}
+
+## @description  docker kill the container on SIGTERM
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+function docker_signal_handler
+{
+  declare cid
+
+  cid=$(cat "${PATCH_DIR}/cidfile")
+
+  yetus_error "ERROR: Caught signal. Killing docker container:"
+  dockercmd kill "${cid}"
+  yetus_error "ERROR: Exiting."
+  cleanup_and_exit 143 # 128 + 15 -- SIGTERM
+}
+
+## @description  Switch over to a Docker container
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        args
+function docker_handler
+{
+  PATCH_DIR=$(relative_dir "${PATCH_DIR}")
+
+  docker_cleanup
+  determine_user
+  docker_run_image
+}


Mime
View raw message