This is an automated email from the ASF dual-hosted git repository.

aw pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/yetus.git


The following commit(s) were added to refs/heads/main by this push:
     new fc27195  YETUS-1059. Github Status Recovery Tool (#184)
fc27195 is described below

commit fc27195755bbb469c9f8c41ea29db194e017e39b
Author: Allen Wittenauer <[email protected]>
AuthorDate: Mon Nov 2 06:18:00 2020 -0800

    YETUS-1059. Github Status Recovery Tool (#184)
---
 Jenkinsfile                                        |  28 ++-
 .../precommit/github-status-recovery.html.md       |  50 ++++
 .../in-progress/precommit/index.html.md            |   1 +
 .../in-progress/precommit/robots/jenkins.html.md   |  23 +-
 precommit/src/main/shell/core.d/linecomments.sh    | 132 +++++++++++
 precommit/src/main/shell/github-status-recovery.sh | 188 +++++++++++++++
 precommit/src/main/shell/test-patch.d/github.sh    | 259 ++++++++++++++++++++-
 precommit/src/main/shell/test-patch.sh             | 114 +--------
 8 files changed, 675 insertions(+), 120 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index 0840c93..6a59fdc 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -104,9 +104,6 @@ pipeline {
                 YETUS_ARGS+=(--jira-password="${JIRA_PASSWORD}")
                 YETUS_ARGS+=(--jira-user="${JIRA_USER}")
 
-                # disable per-line comments
-                YETUS_ARGS+=(--linecomments='')
-
                 # pylint settings
                 YETUS_ARGS+=('--pylint=pylint2')
 
@@ -167,6 +164,31 @@ pipeline {
   post {
     always {
       script {
+
+        // Publish status if it was missed
+        withCredentials([usernamePassword(credentialsId: 
'apache-yetus-at-github.com',
+                         passwordVariable: 'GITHUB_TOKEN',
+                         usernameVariable: 'GITHUB_USER')]) {
+            sh '''#!/usr/bin/env bash
+
+                # enable writing back to Github
+                YETUS_ARGS+=(--github-token="${GITHUB_TOKEN}")
+                
YETUS_ARGS+=("--patch-dir=${WORKSPACE}/${YETUS_RELATIVE_PATCHDIR}")
+
+                if [[ "${USE_DEBUG_FLAG}" == true ]]; then
+                  YETUS_ARGS+=("--debug")
+                fi
+
+                # run test-patch from the source tree specified up above
+                
TESTPATCHBIN=${WORKSPACE}/src/precommit/src/main/shell/github-status-recovery.sh
+
+                # execute! (we are using bash instead of the
+                # bin in case the perms get messed up)
+                /usr/bin/env bash "${TESTPATCHBIN}" "${YETUS_ARGS[@]}" 
${EXTRA_ARGS} || true
+
+                '''
+        }
+
         // Publish JUnit results
         try {
             junit "${env.YETUS_RELATIVE_PATCHDIR}/junit-report.xml"
diff --git 
a/asf-site-src/source/documentation/in-progress/precommit/github-status-recovery.html.md
 
b/asf-site-src/source/documentation/in-progress/precommit/github-status-recovery.html.md
new file mode 100644
index 0000000..0cb6740
--- /dev/null
+++ 
b/asf-site-src/source/documentation/in-progress/precommit/github-status-recovery.html.md
@@ -0,0 +1,50 @@
+<!---
+  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.
+-->
+
+# GitHub Status Recovery
+
+<!-- MarkdownTOC levels="1,2,3" autolink="true" indent="  " bullets="*" 
bracket="round" -->
+
+* [Problem Statement](#problem-statement)
+* [Usage](#usage)
+* [Disabling Annotations](#disabling-annotations)
+
+<!-- /MarkdownTOC -->
+
+# Problem Statement
+
+For CI systems that use GitHub outside of GitHub Actions, they may make 
available a GitHub Checks token.
+Unfortunately, as of this writing (2020-10-30), GitHub sets the expiry of such 
a token to 1 hour.
+For some users of Apache Yetus, their precommit job may take longer than one 
hour.  In order to workaround
+this limitation, the `github-status-recovery` program may be used.
+
+# Usage
+
+The usage is relatively simple:
+
+```bash
+$ github-status-recovery --patch-dir=<pre-existing patch directory> 
--github-token=<token>
+```
+
+If the previous run of `test-patch` failed to write the status, 
`github-status-recovery` will
+re-process the saved JSON files as well as write GitHub Checks Annotations if 
they exist.
+
+# Disabling Annotations
+
+If for some reason you do not wish annotations to be written, they may be 
disabled with `--github-annotations=false`.
diff --git 
a/asf-site-src/source/documentation/in-progress/precommit/index.html.md 
b/asf-site-src/source/documentation/in-progress/precommit/index.html.md
index ed0f561..b9d3a9f 100644
--- a/asf-site-src/source/documentation/in-progress/precommit/index.html.md
+++ b/asf-site-src/source/documentation/in-progress/precommit/index.html.md
@@ -156,6 +156,7 @@ Language Support, Licensing, and more:
 capacities without needing to use the full `test-patch` runtime:
 
 * [docker-cleanup](docker-cleanup) - safe removal of Docker resources for 
multi-executor CI systems
+* [github-status-recovery](github-status-recovery) - Apache Yetus status on 
GitHub, even for long running jobs
 * [jenkins-admin](admin) - Jenkins<->JIRA patch bridge
 * [qbt](qbt) - Quality Build Tool, for branch-specific testing
 * [smart-apply-patch](smart-apply-patch) - CLI manipulation and query of patch 
files, PRs, and more
diff --git 
a/asf-site-src/source/documentation/in-progress/precommit/robots/jenkins.html.md
 
b/asf-site-src/source/documentation/in-progress/precommit/robots/jenkins.html.md
index 4d81947..3de1b8c 100644
--- 
a/asf-site-src/source/documentation/in-progress/precommit/robots/jenkins.html.md
+++ 
b/asf-site-src/source/documentation/in-progress/precommit/robots/jenkins.html.md
@@ -90,8 +90,27 @@ for the optimal `test-patch` experience.  Configure up to 
the "Configuring the G
 ...
 ```
 
-Doing so will enable in many circumstances a bit more functionality, such as
-GitHub Statuses.
+Doing so will enable in many circumstances a bit more functionality, such as 
GitHub Statuses.
+
+## Enabling GitHub Status Recovery
+
+If the Apache Yetus section of your job typically runs longer than 1 hour and 
you use GitHub as the primary bugsystem,
+it is recommend to use the `github-status-recovery` utility in the `post` 
section of your `Jenkinsfile`. For example:
+
+```groovy
+  post {
+    always {
+      script {
+        // Publish status if it was missed
+        withCredentials([usernamePassword(credentialsId: github-app',
+                         passwordVariable: 'GITHUB_TOKEN',
+                         usernameVariable: 'GITHUB_USER')]) {
+            sh '''github-status-recovery --patch-dir="${PATCH_DIR}"" 
--github-token="${GITHUB_TOKEN}"'''
+        }
+      }
+    }
+  }
+```
 
 See also:
 
diff --git a/precommit/src/main/shell/core.d/linecomments.sh 
b/precommit/src/main/shell/core.d/linecomments.sh
new file mode 100755
index 0000000..4ccd5e0
--- /dev/null
+++ b/precommit/src/main/shell/core.d/linecomments.sh
@@ -0,0 +1,132 @@
+#!/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
+
+## @description  Queue up comments to write into bug systems
+## @description  that have code review support, if such support
+## @description  enabled/available.
+## @description  File should be in the form of "file:line[:column]:comment"
+## @audience     public
+## @stability    evolving
+## @replaceable  no
+## @param        plugin
+## @param        filename
+function bugsystem_linecomments_queue
+{
+  declare plugin=$1
+  declare fn=$2
+  declare line
+  declare linenum
+  declare text
+  declare columncheck
+  declare column
+  declare rol
+  declare file
+
+  if [[ -z "${BUGLINECOMMENTS}" ]]; then
+    return 0
+  fi
+
+  for line in "${VOTE_FILTER[@]}"; do
+    if [[ "${plugin}" == "${line}" ]]; then
+      return 0
+    fi
+  done
+
+  pushd "${BASEDIR}" >/dev/null || return 1
+  while read -r line; do
+    file=${line%%:*}
+
+    if [[ ! -e "${file}" ]]; then
+      continue
+    fi
+
+    rol=${line/#${file}:}
+    if [[ "${file}" =~ ^\./ ]]; then
+      file=${file:2}
+    fi
+
+    linenum=${rol%%:*}
+    rol=${rol/#${linenum}:}
+    columncheck=${rol%%:*}
+    if [[ "${columncheck}" =~ ^[0-9]+$ ]]; then
+      column=${columncheck}
+      text=${rol/#${column}:}
+    else
+      column="0"
+      text=${rol}
+    fi
+
+    echo "${file}:${linenum}:${column}:${plugin}:${text}" >> 
"${PATCH_DIR}/results-full.txt"
+
+  done < "${fn}"
+
+  popd >/dev/null || return 1
+
+}
+
+## @description  Write all of the bugsystem linecomments
+## @audience     public
+## @stability    evolving
+## @replaceable  no
+function bugsystem_linecomments_trigger
+{
+  declare plugin
+  declare fn
+  declare line
+  declare linenum
+  declare text
+  declare column
+
+  if [[ ! -f "${PATCH_DIR}/results-full.txt" ]]; then
+    return 0
+  fi
+
+  # sort the file such that all files and lines are now next to each other
+  sort -k1,1 -k2,2n -k3,3n -k4,4 "${PATCH_DIR}/results-full.txt" > 
"${PATCH_DIR}/linecomments-sorted.txt"
+  mv "${PATCH_DIR}/linecomments-sorted.txt" "${PATCH_DIR}/results-full.txt"
+
+  while read -r line;do
+    fn=${line%%:*}
+    rol=${line/#${fn}:}
+    linenum=${rol%%:*}
+    rol=${rol/#${linenum}:}
+    column=${rol%%:*}
+    rol=${rol/#${column}:}
+    plugin=${rol%%:*}
+    text=${rol/#${plugin}:}
+
+    for bugs in ${BUGLINECOMMENTS}; do
+      if declare -f "${bugs}_linecomments" >/dev/null;then
+        "${bugs}_linecomments" "${fn}" "${linenum}" "${column}" "${plugin}" 
"${text}"
+      fi
+    done
+  done < "${PATCH_DIR}/results-full.txt"
+
+  for bugs in ${BUGLINECOMMENTS}; do
+    if declare -f "${bugs}_linecomments_end" >/dev/null;then
+      "${bugs}_linecomments_end"
+    fi
+  done
+}
\ No newline at end of file
diff --git a/precommit/src/main/shell/github-status-recovery.sh 
b/precommit/src/main/shell/github-status-recovery.sh
new file mode 100755
index 0000000..97bf95a
--- /dev/null
+++ b/precommit/src/main/shell/github-status-recovery.sh
@@ -0,0 +1,188 @@
+#!/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.
+
+# no shelldocs required from this file
+# SHELLDOC-IGNORE
+
+# 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)
+BINNAME=${this##*/}
+BINNAME=${BINNAME%.sh}
+#shellcheck disable=SC2034
+STARTINGDIR=$(pwd)
+#shellcheck disable=SC2034
+USER_PARAMS=("$@")
+#shellcheck disable=SC2034
+QATESTMODE=false
+#shellcheck disable=SC2034
+ISODATESTART=$(date +"%Y-%m-%dT%H:%M:%SZ")
+
+## @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
+}
+
+## @description  import plugins then remove the stuff we don't need
+## @audience     public
+## @stability    stable
+## @replaceable  no
+function import_including_github
+{
+  #shellcheck disable=SC2034
+  ENABLED_PLUGINS='github'
+  importplugins
+  yetus_debug "Removing BUILDTOOLS, TESTTYPES, and TESTFORMATS from installed 
plug-in list"
+  #shellcheck disable=SC2034
+  BUILDTOOLS=()
+  #shellcheck disable=SC2034
+  TESTTYPES=()
+  #shellcheck disable=SC2034
+  TESTFORMATS=()
+  #shellcheck disable=SC2034
+  BUGSYSTEMS=('github')
+  #shellcheck disable=SC2034
+  BUGLINECOMMENTS='github'
+  #shellcheck disable=SC2034
+  GITHUB_STATUS_RECOVER_TOOL=true
+  GITHUB_CHECK_ANNOTATIONS=true
+}
+
+## @description  Setup the default global variables
+## @audience     public
+## @stability    stable
+## @replaceable  no
+function setup_defaults
+{
+  common_defaults
+}
+
+## @description  Interpret the command line parameters
+## @audience     private
+## @stability    stable
+## @replaceable  no
+## @param        $@
+## @return       May exit on failure
+function parse_args
+{
+  declare i
+  common_args "$@"
+
+  for i in "$@"; do
+    case ${i} in
+      --github-annotations=*)
+        delete_parameter "${i}"
+        GITHUB_CHECK_ANNOTATIONS="${i#*=}"
+      ;;
+    esac
+  done
+}
+
+## @description  Print the usage information
+## @audience     public
+## @stability    stable
+## @replaceable  no
+function yetus_usage
+{
+  import_including_github
+  github_usage
+
+  echo "${BINNAME} [OPTIONS]"
+
+  yetus_add_option "--github-annotations=<bool>" "Enable GitHub Checks 
Annoations [default: ${GITHUB_CHECK_ANNOTATIONS}]"
+  yetus_add_option "--curl-cmd=<cmd>" "The 'curl' command to use (default 
'curl')"
+  yetus_add_option "--debug" "If set, then output some extra stuff to stderr"
+  yetus_add_option "--grep-cmd=<cmd>" "The 'grep' command to use (default 
'grep')"
+  yetus_add_option "--ignore-unknown-options=<bool>" "Continue despite unknown 
options (default: ${IGNORE_UNKNOWN_OPTIONS})"
+  yetus_add_option "--patch-dir=<dir>" "The directory for working and output 
files (default '/tmp/test-patch-${PROJECT_NAME}/pid')"
+
+  yetus_generic_columnprinter "${YETUS_OPTION_USAGE[@]}"
+  yetus_reset_usage
+}
+
+## @description  Large display for the user console
+## @audience     public
+## @stability    stable
+## @replaceable  no
+## @param        string
+## @return       large chunk of text
+function big_console_header
+{
+  local text="$*"
+  local spacing=$(( (75+${#text}) /2 ))
+  printf '\n\n'
+  echo 
"============================================================================"
+  echo 
"============================================================================"
+  printf '%*s\n'  ${spacing} "${text}"
+  echo 
"============================================================================"
+  echo 
"============================================================================"
+  printf '\n\n'
+}
+
+## @description setup the parameter tracker for param errors
+## @audience    private
+## @stability   evolving
+function setup_parameter_tracker
+{
+  declare i
+
+  for i in "${USER_PARAMS[@]}"; do
+    if [[ "${i}" =~ ^-- ]]; then
+      i=${i%=*}
+      PARAMETER_TRACKER+=("${i}")
+    fi
+  done
+}
+
+trap "cleanup_and_exit 1" HUP INT QUIT TERM
+
+setup_parameter_tracker
+
+import_core
+
+setup_defaults
+
+parse_args "$@"
+
+import_including_github
+
+parse_args_plugins "$@"
+
+if [[ "${#PARAMETER_TRACKER}" -gt 0 ]]; then
+  yetus_error "ERROR: Unprocessed flag(s): ${PARAMETER_TRACKER[*]}"
+  if [[ "${IGNORE_UNKNOWN_OPTIONS}" == false ]]; then
+    cleanup_and_exit 1
+  fi
+fi
+
+github_status_recovery
diff --git a/precommit/src/main/shell/test-patch.d/github.sh 
b/precommit/src/main/shell/test-patch.d/github.sh
index eb01f1e..cdfec87 100755
--- a/precommit/src/main/shell/test-patch.d/github.sh
+++ b/precommit/src/main/shell/test-patch.d/github.sh
@@ -36,6 +36,8 @@ GITHUB_REPO=""
 GITHUB_TOKEN="${GITHUB_TOKEN-}"
 GITHUB_ISSUE=""
 GITHUB_USE_EMOJI_VOTE=false
+GITHUB_STATUS_RECOVERY_COUNTER=1
+GITHUB_STATUS_RECOVER_TOOL=false
 declare -a GITHUB_AUTH
 
 # private globals...
@@ -47,7 +49,9 @@ function github_usage
   yetus_add_option "--github-base-url=<url>" "The URL of the github server 
(default:'${GITHUB_BASE_URL}')"
   yetus_add_option "--github-repo=<repo>" "github repo to use 
(default:'${GITHUB_REPO}')"
   yetus_add_option "--github-token=<token>" "The token to use to read/write to 
github"
-  yetus_add_option "--github-use-emoji-vote" "Whether to use emoji to 
represent the vote result on github [default: ${GITHUB_USE_EMOJI_VOTE}]"
+  if [[ "${GITHUB_STATUS_RECOVER_TOOL}" == false ]]; then
+    yetus_add_option "--github-use-emoji-vote" "Whether to use emoji to 
represent the vote result on github [default: ${GITHUB_USE_EMOJI_VOTE}]"
+  fi
 }
 
 function github_parse_args
@@ -454,6 +458,129 @@ function github_locate_patch
   esac
 }
 
+## @description Generate a Github Check Run ID
+## @stability evolving
+## @audience  private
+function github_start_checkrun
+{
+  declare tempfile="${PATCH_DIR}/ghcheckrun.$$.${RANDOM}"
+  declare output="${PATCH_DIR}/ghcheckrun.json"
+
+  if [[ -z "${GITHUB_SHA}" ]]; then
+    GITHUB_SHA=$("${GREP}" \"sha\" "${PATCH_DIR}/github-pull.json" 2>/dev/null 
\
+      | head -1 \
+      | cut -f4 -d\")
+  fi
+
+  if [[ -z "${GITHUB_SHA}" ]]; then
+    return 0
+  fi
+
+  # don't need this under GHA
+  if [[ "${ROBOTTYPE}" == 'githubactions' ]]; then
+    return 0
+  fi
+
+  if [[ "${OFFLINE}" == true ]]; then
+    return 0
+  fi
+
+  if [[ "${#GITHUB_AUTH[@]}" -eq 0 ]]; then
+    return 0
+  fi
+
+  {
+    printf "{"
+    echo "\"name\":\"Apache Yetus ${ROBOTTYPE}\","
+    echo "\"head_sha\": \"${GITHUB_SHA}\","
+    echo "\"details_url\": \"${BUILD_URL}${BUILD_URL_CONSOLE}\","
+    echo "\"external_id\": \"${INSTANCE}\","
+    echo "\"status\": \"in_progress\","
+    echo "\"started_at\": \"${ISODATESTART}\""
+    # external_id  instance_id?
+    # status queued, in_progress, completed
+    # started_at ISO-8601
+    # conclusion , required for status=completed, completed_at=value
+    #  success, failure, neutral, cancelled, skipped, timed_out, 
action_required
+    # completed_at  ISO-8601
+    # output  see github docs @ 
https://docs.github.com/en/rest/reference/checks#update-a-check-run
+    echo "}"
+  } > "${tempfile}"
+
+  "${CURL}" --silent --fail -X POST \
+    -H "Accept: application/vnd.github.antiope-preview+json" \
+    -H "Content-Type: application/json" \
+     "${GITHUB_AUTH[@]}" \
+    -d @"${tempfile}" \
+    --location \
+    "${GITHUB_API_URL}/repos/${GITHUB_REPO}/check-runs" \
+    --output "${output}" 2>/dev/null
+
+  GITHUB_CHECK_RUN_ID=$("${GREP}" \"id\" "${output}" 2>/dev/null \
+    | head -1 \
+    | cut -f2 -d: \
+    | cut -f1 -d,)
+  GITHUB_CHECK_RUN_ID=${GITHUB_CHECK_RUN_ID// /}
+}
+
+## @description Generate a Github Check Run ID
+## @stability evolving
+## @audience  private
+function github_end_checkrun
+{
+  declare result=$1
+  declare tempfile="${PATCH_DIR}/ghcheckrun.$$.${RANDOM}"
+  declare output="${PATCH_DIR}/ghcheckrun-final.json"
+  declare conclusion
+
+  # don't need this under GHA
+  if [[ "${ROBOTTYPE}" == 'githubactions' ]]; then
+    return 0
+  fi
+
+  if [[ "${OFFLINE}" == true ]]; then
+    return 0
+  fi
+
+  if [[ "${#GITHUB_AUTH[@]}" -eq 0 ]]; then
+    return 0
+  fi
+
+  if [[ "${result}" -eq 0 ]]; then
+    conclusion="success"
+  else
+    conclusion="failure"
+  fi
+
+  finishdate=$(date +"%Y-%m-%dT%H:%M:%SZ")
+
+  {
+    printf "{"
+    echo "\"conclusion\":\"${conclusion}\","
+    echo "\"status\": \"completed\","
+    echo "\"completed_at\": \"${finishdate}\""
+    echo "}"
+  } > "${tempfile}"
+
+  "${CURL}" --fail --silent -X PATCH \
+    -H "Accept: application/vnd.github.antiope-preview+json" \
+    -H "Content-Type: application/json" \
+     "${GITHUB_AUTH[@]}" \
+    -d @"${tempfile}" \
+    --location \
+    "${GITHUB_API_URL}/repos/${GITHUB_REPO}/check-runs/${GITHUB_CHECK_RUN_ID}" 
\
+    --output "${output}" 2>/dev/null
+  rm "${tempfile}"
+}
+
+## @description Write a Github Checks Annotation
+## @param     filename
+## @param     linenum
+## @param     column
+## @param     plugin
+## @param     text
+## @stability evolving
+## @audience  private
 function github_linecomments
 {
   declare file=$1
@@ -462,6 +589,10 @@ function github_linecomments
   declare plugin=$4
   shift 4
   declare text=$*
+  declare tempfile="${PATCH_DIR}/ghcomment.$$.${RANDOM}"
+  declare header
+  declare -a linehandler
+  declare -a colhandler
 
   if [[ "${ROBOTTYPE}" == 'githubactions' ]]; then
     if [[ -z "${column}" ]] || [[ "${column}" == 0 ]]; then
@@ -471,6 +602,69 @@ function github_linecomments
     fi
     return 0
   fi
+
+  if [[ "${OFFLINE}" == true ]]; then
+    echo "Github Plugin: Running in offline, comment skipped."
+    return 0
+  fi
+
+  if [[ "${#GITHUB_AUTH[@]}" -eq 0 ]]; then
+    return 0
+  fi
+
+  if [[ -z "${GITHUB_CHECK_RUN_ID}" ]]; then
+    if ! github_start_checkrun; then
+      yetus_error "ERROR: Cannot generate a Github Check Run ID"
+      return 1
+    fi
+  fi
+
+  linehandler=(\"start_line\": "${linenum},")
+  linehandler+=(\"end_line\": "${linenum},")
+
+  if [[ -z "${column}" ]] || [[ "${column}" == 0 ]]; then
+    colhandler=()
+  else
+    colhandler=(\"start_column\": "${column},")
+    colhandler+=(\"end_column\": "${column},")
+  fi
+
+  newtext=$(echo "${text[*]}" | "${SED}" -e 's,\\,\\\\,g' \
+        -e 's,\",\\\",g' \
+        -e 's,$,\\r\\n,g' \
+      | tr -d '\n')
+
+  if [[ "${ROBOTTYPE}" ]]; then
+    header="Apache Yetus(${ROBOTTYPE})"
+  else
+    header="Apache Yetus"
+  fi
+
+  cat <<EOF > "${tempfile}"
+{
+  "output": {
+    "title": "${header}",
+    "summary": "Precommit Problem",
+    "annotations" : [{
+      "path": "${file}",
+      ${linehandler[@]}
+      ${colhandler[@]}
+      "annotation_level": "failure",
+      "message": "${newtext}"
+    }]
+  }
+}
+EOF
+
+  "${CURL}" --fail -X PATCH \
+    -H "Accept: application/vnd.github.antiope-preview+json" \
+    -H "Content-Type: application/json" \
+     "${GITHUB_AUTH[@]}" \
+    -d @"${tempfile}" \
+    --silent --location \
+    "${GITHUB_API_URL}/repos/${GITHUB_REPO}/check-runs/${GITHUB_CHECK_RUN_ID}" 
\
+    2>/dev/null
+  rm "${tempfile}"
 }
 
 ## @description Write the contents of a file to github
@@ -663,10 +857,15 @@ function github_write_comment
 ## @stability    evolving
 ## @replaceable  no
 ## @param        runresult
-function github_status_write()
+function github_status_write
 {
   declare filename=$1
   declare retval=0
+  declare 
recoverydir="${PATCH_DIR}/github-status-retry/${GITHUB_REPO}/${GIT_BRANCH_SHA}"
+
+  if [[ "${OFFLINE}" == true ]]; then
+    return 0
+  fi
 
   if [[ "${#GITHUB_AUTH[@]}" -lt 1 ]]; then
     echo "Github Plugin: no credentials provided to write a status."
@@ -684,11 +883,59 @@ function github_status_write()
 
   retval=$?
   if [[ ${retval} -gt 0 ]]; then
-    echo "githubstatus-report: Failed to write status. Maybe the credential 
does not have write access to repo:status."
+    yetus_error "ERROR: Failed to write github status. Token expired or 
missing repo:status write?"
+    if [[ "${GITHUB_STATUS_RECOVER_TOOL}" == false ]]; then
+      mkdir -p "${recoverydir}"
+      cp -p "${tempfile}" 
"${recoverydir}/${GITHUB_STATUS_RECOVERY_COUNTER}.json"
+      ((GITHUB_STATUS_RECOVERY_COUNTER=GITHUB_STATUS_RECOVERY_COUNTER+1))
+    fi
   fi
   return ${retval}
 }
 
+## @description  Write a github status
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        runresult
+function github_status_recovery
+{
+  declare filename
+  declare retval=0
+  declare retrydir
+
+  # get the first filename
+  filename=$(find "${PATCH_DIR}/github-status-retry" -type f -name '1.json' 
2>/dev/null)
+
+  if [[ -z "${filename}" ]]; then
+    echo "No retry directory found in ${PATCH_DIR}. Maybe it was successful?"
+    return 0
+  fi
+
+  retrydir="${filename##*/github-status-retry/}"
+  GITHUB_REPO=$(echo "${retrydir}" | cut -f1-2 -d/)
+  GIT_BRANCH_SHA=$(echo "${retrydir}" | cut -f3 -d/)
+
+
+  github_initialize
+
+  if [[ "${#GITHUB_AUTH[@]}" -lt 1 ]]; then
+    echo "Github Plugin: no credentials provided to write a status."
+    return 1
+  fi
+
+  while read -r; do
+    github_status_write "${REPLY}"
+    retval=$?
+  done < <(find "${PATCH_DIR}/github-status-retry" -type f)
+
+  if [[ "${GITHUB_CHECK_ANNOTATIONS}" == true ]]; then
+    bugsystem_linecomments_trigger
+  fi
+
+  return ${retval}
+}
+
 ## @description  Print out the finished details to the Github PR
 ## @audience     private
 ## @stability    evolving
@@ -711,6 +958,10 @@ function github_finalreport
   declare -i i=0
   declare header
 
+  if [[ "${OFFLINE}" == true ]]; then
+    return 0
+  fi
+
   big_console_header "Adding GitHub Statuses"
 
   if [[ "${#GITHUB_AUTH[@]}" -lt 1 ]]; then
@@ -723,6 +974,8 @@ function github_finalreport
     return 0
   fi
 
+  github_end_checkrun "${result}"
+
   url=$(get_artifact_url)
 
   if [[ "${ROBOTTYPE}" ]]; then
diff --git a/precommit/src/main/shell/test-patch.sh 
b/precommit/src/main/shell/test-patch.sh
index f0cf777..93d2e12 100755
--- a/precommit/src/main/shell/test-patch.sh
+++ b/precommit/src/main/shell/test-patch.sh
@@ -68,6 +68,8 @@ function setup_defaults
 
   common_defaults
   GLOBALTIMER=$("${AWK}" 'BEGIN {srand(); print srand()}')
+  # shellcheck disable=SC2034
+  ISODATESTART=$(date +"%Y-%m-%dT%H:%M:%SZ")
 
   set_yetus_version
 
@@ -2177,118 +2179,6 @@ function check_unittests
   return 0
 }
 
-## @description  Queue up comments to write into bug systems
-## @description  that have code review support, if such support
-## @description  enabled/available.
-## @description  File should be in the form of "file:line[:column]:comment"
-## @audience     public
-## @stability    evolving
-## @replaceable  no
-## @param        plugin
-## @param        filename
-function bugsystem_linecomments_queue
-{
-  declare plugin=$1
-  declare fn=$2
-  declare line
-  declare linenum
-  declare text
-  declare columncheck
-  declare column
-  declare rol
-  declare file
-
-  if [[ -z "${BUGLINECOMMENTS}" ]]; then
-    return 0
-  fi
-
-  for line in "${VOTE_FILTER[@]}"; do
-    if [[ "${plugin}" == "${line}" ]]; then
-      return 0
-    fi
-  done
-
-  pushd "${BASEDIR}" >/dev/null || return 1
-  while read -r line; do
-    file=${line%%:*}
-
-    if [[ ! -e "${file}" ]]; then
-      continue
-    fi
-
-    rol=${line/#${file}:}
-    if [[ "${file}" =~ ^\./ ]]; then
-      file=${file:2}
-    fi
-
-    linenum=${rol%%:*}
-    rol=${rol/#${linenum}:}
-    columncheck=${rol%%:*}
-    if [[ "${columncheck}" =~ ^[0-9]+$ ]]; then
-      column=${columncheck}
-      text=${rol/#${column}:}
-    else
-      column="0"
-      text=${rol}
-    fi
-
-    echo "${file}:${linenum}:${column}:${plugin}:${text}" >> 
"${PATCH_DIR}/linecomments-in.txt"
-
-  done < "${fn}"
-
-  popd >/dev/null || return 1
-
-}
-
-## @description  Write all of the bugsystem linecomments
-## @audience     public
-## @stability    evolving
-## @replaceable  no
-function bugsystem_linecomments_trigger
-{
-  declare plugin
-  declare fn
-  declare line
-  declare linenum
-  declare text
-  declare column
-
-  if [[ ! -f "${PATCH_DIR}/linecomments-in.txt" ]]; then
-    return 0
-  fi
-
-  # sort the file such that all files and lines are now next to each other
-  sort -k1,1 -k2,2n -k3,3n -k4,4 "${PATCH_DIR}/linecomments-in.txt" > 
"${PATCH_DIR}/linecomments-sorted.txt"
-
-  while read -r line;do
-    fn=${line%%:*}
-    rol=${line/#${fn}:}
-    linenum=${rol%%:*}
-    rol=${rol/#${linenum}:}
-    column=${rol%%:*}
-    rol=${rol/#${column}:}
-    plugin=${rol%%:*}
-    text=${rol/#${plugin}:}
-
-    for bugs in ${BUGLINECOMMENTS}; do
-      if declare -f "${bugs}_linecomments" >/dev/null;then
-        "${bugs}_linecomments" "${fn}" "${linenum}" "${column}" "${plugin}" 
"${text}"
-      fi
-    done
-  done < "${PATCH_DIR}/linecomments-sorted.txt"
-
-  for bugs in ${BUGLINECOMMENTS}; do
-    if declare -f "${bugs}_linecomments_end" >/dev/null;then
-      "${bugs}_linecomments_end"
-    fi
-  done
-
-  if [[ "${YETUS_SHELL_SCRIPT_DEBUG}" = true ]]; then
-    yetus_debug "Keeping linecomments files for debugging"
-  else
-    rm "${PATCH_DIR}/linecomments-in.txt" 
"${PATCH_DIR}/linecomments-sorted.txt"
-  fi
-}
 
 ## @description  Write the final output to the selected bug system
 ## @audience     private

Reply via email to