Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ GitHub Action support is available in two different ways. There are some settin
* Annotations will be used to mark problems in the files for those plug-ins that support this feature and
if `--linecomments` has `github` as a configured bug system (the default).
* Statuses will be added if the GitHub Token gives permission.
* Job Summary will be written with a Markdown-formatted report of the test results, visible directly on the
workflow run page without downloading artifacts.

## Workflow Action

Expand Down Expand Up @@ -108,6 +110,23 @@ TRIGGER: ${GITHUB_ACTIONS}=True

GitHub Actions support has only been tested on the ubuntu-latest image. It automatically configures `--patch-dir` to be `${GITHUB_WORKSAPCE}/yetus` if not previously set.

## Job Summary

When running under GitHub Actions, Apache Yetus automatically writes a summary of the test results to the
[Job Summary](https://github.blog/2022-05-09-supercharging-github-actions-with-job-summaries/). This provides
immediate visibility of pass/fail status and details directly on the workflow run page, without needing to
download artifacts or parse log files.

The Job Summary includes:

* Overall pass/fail status with vote counts
* Vote table showing each subsystem's result, runtime, and comments
* Failed tests section (if any tests failed)
* Links to log files (if artifact URLs are available)

This feature requires no configuration and is automatically enabled when the `GITHUB_STEP_SUMMARY` environment
variable is present (which GitHub Actions sets automatically).

See also:

* Apache Yetus' [workflow action source](https://github.com/apache/yetus-test-patch-action) for lower level details on the workflow action implementation.
Expand Down
6 changes: 5 additions & 1 deletion precommit/src/main/shell/core.d/docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -939,9 +939,13 @@ function docker_handler

determine_user

# need to call this explicitly
# need to call these explicitly (not in plugin lists)
console_docker_support

if declare -f githubactions_docker_support >/dev/null; then
githubactions_docker_support
fi

for plugin in ${PROJECT_NAME} ${BUILDTOOL} "${BUGSYSTEMS[@]}" "${TESTTYPES[@]}" "${TESTFORMATS[@]}"; do
if declare -f "${plugin}_docker_support" >/dev/null; then
"${plugin}_docker_support"
Expand Down
153 changes: 152 additions & 1 deletion precommit/src/main/shell/robots.d/githubactions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,158 @@ function githubactions_set_plugin_defaults
GITHUB_REPO="${GITHUB_REPOSITORY}"
}

## @description Docker support for GitHub Actions
## @audience private
## @stability evolving
## @replaceable no
function githubactions_docker_support
{
if [[ -z "${GITHUB_STEP_SUMMARY}" ]]; then
return 0
fi

if [[ ! -f "${GITHUB_STEP_SUMMARY}" ]]; then
return 0
fi

DOCKER_EXTRAARGS+=("-v" "${GITHUB_STEP_SUMMARY}:${DOCKER_WORK_DIR}/step_summary.md")
GITHUB_STEP_SUMMARY="${DOCKER_WORK_DIR}/step_summary.md"
add_docker_env GITHUB_STEP_SUMMARY
}

function githubactions_cleanup_and_exit
{
echo "::endgroup::"
}
}

## @description Write a summary report to GitHub Actions Job Summary
## @audience private
## @stability evolving
## @replaceable no
function githubactions_finalreport
{
declare -i i=0
declare ourstring
declare vote
declare subs
declare ela
declare calctime
declare logfile
declare comment
declare url
declare emoji
declare loglink

if [[ -z "${GITHUB_STEP_SUMMARY}" ]]; then
return 0
fi

if [[ ! -w "${GITHUB_STEP_SUMMARY}" ]]; then
yetus_error "WARNING: GITHUB_STEP_SUMMARY (${GITHUB_STEP_SUMMARY}) is not writable"
return 0
fi

big_console_header "Writing GitHub Actions Job Summary"

url=$(get_artifact_url)

{
if [[ ${RESULT} == 0 ]]; then
printf '## :confetti_ball: +1 overall\n\n'
else
printf '## :broken_heart: -1 overall\n\n'
fi

i=0
until [[ ${i} -ge ${#TP_HEADER[@]} ]]; do
printf '%s\n\n' "${TP_HEADER[i]}"
((i=i+1))
done

printf '| Vote | Subsystem | Runtime | Logfile | Comment |\n'
printf '|:----:|----------:|--------:|:-------:|:--------|\n'

i=0
until [[ ${i} -ge ${#TP_VOTE_TABLE[@]} ]]; do
ourstring=$(echo "${TP_VOTE_TABLE[i]}" | tr -s ' ')
vote=$(echo "${ourstring}" | cut -f2 -d\| | tr -d ' ')
subs=$(echo "${ourstring}" | cut -f3 -d\|)
ela=$(echo "${ourstring}" | cut -f4 -d\|)
calctime=$(clock_display "${ela}")
logfile=$(echo "${ourstring}" | cut -f5 -d\| | tr -d ' ')
comment=$(echo "${ourstring}" | cut -f6 -d\|)

if [[ "${vote}" = "H" ]]; then
printf '| | | | | _%s_ |\n' "${comment}"
((i=i+1))
continue
fi

# Honor GITHUB_USE_EMOJI_VOTE setting
if [[ ${GITHUB_USE_EMOJI_VOTE} == true ]]; then
case ${vote} in
1|"+1")
emoji="+1 :green_heart:"
;;
-1)
emoji="-1 :x:"
;;
0)
emoji="+0 :ok:"
;;
-0)
emoji="-0 :warning:"
;;
*)
emoji=${vote}
;;
esac
else
emoji="${vote}"
fi

# Format logfile as link if URL is available
if [[ -n "${logfile}" ]]; then
if [[ -n "${url}" ]]; then
loglink=$(echo "${logfile}" | "${SED}" -e "s,@@BASE@@,${url},g")
loglink="[${logfile/@@BASE@@\//}](${loglink})"
else
loglink="${logfile/@@BASE@@\//}"
fi
else
loglink=""
fi

printf '| %s | %s | %s | %s | %s |\n' \
"${emoji}" \
"${subs}" \
"${calctime}" \
"${loglink}" \
"${comment}"

((i=i+1))
done

if [[ ${#TP_TEST_TABLE[@]} -gt 0 ]]; then
printf '\n### Failed Tests\n\n'
printf '| Reason | Tests |\n'
printf '|-------:|:------|\n'
i=0
until [[ ${i} -ge ${#TP_TEST_TABLE[@]} ]]; do
echo "${TP_TEST_TABLE[i]}"
((i=i+1))
done
fi

printf '\n### Subsystem Report\n\n'
printf '| Subsystem | Report/Notes |\n'
printf '|----------:|:-------------|\n'

i=0
until [[ ${i} -ge ${#TP_FOOTER_TABLE[@]} ]]; do
comment=$(echo "${TP_FOOTER_TABLE[i]}" | "${SED}" -e "s,@@BASE@@,${url},g")
printf '%s\n' "${comment}"
((i=i+1))
done
} >> "${GITHUB_STEP_SUMMARY}"
}
175 changes: 175 additions & 0 deletions precommit/src/test/shell/githubactions_finalreport.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
#!/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.

load functions_test_helper

setup_gha() {
# Source the githubactions robot
# shellcheck disable=SC1090
. "${BATS_TEST_DIRNAME}/../../main/shell/robots.d/githubactions.sh"

# Mock required functions
big_console_header() { :; }
clock_display() { echo "$1s"; }
get_artifact_url() { echo ""; }
yetus_error() { echo "$*" >&2; }
SED="sed"

# Set up step summary file
GITHUB_STEP_SUMMARY="${TMP}/step_summary.md"
touch "${GITHUB_STEP_SUMMARY}"
export GITHUB_STEP_SUMMARY

# Initialize arrays and settings
TP_VOTE_TABLE=()
TP_TEST_TABLE=()
TP_HEADER=()
TP_FOOTER_TABLE=()
VERSION="0.0.0-test"
GITHUB_USE_EMOJI_VOTE=false
}

@test "githubactions_finalreport (no GITHUB_STEP_SUMMARY)" {
setup_gha
unset GITHUB_STEP_SUMMARY
run githubactions_finalreport
[ "${status}" -eq 0 ]
}

@test "githubactions_finalreport (GITHUB_STEP_SUMMARY not writable)" {
setup_gha
GITHUB_STEP_SUMMARY="/nonexistent/path/summary.md"
run githubactions_finalreport
[ "${status}" -eq 0 ]
}

@test "githubactions_finalreport (success result)" {
setup_gha
RESULT=0
TP_VOTE_TABLE=("|+1| compile |60||passed|")
run githubactions_finalreport
[ "${status}" -eq 0 ]
grep -q ":confetti_ball:" "${GITHUB_STEP_SUMMARY}"
grep -q "+1 overall" "${GITHUB_STEP_SUMMARY}"
grep -q "compile" "${GITHUB_STEP_SUMMARY}"
}

@test "githubactions_finalreport (failure result)" {
setup_gha
RESULT=1
TP_VOTE_TABLE=("|-1| unit |120||tests failed|")
run githubactions_finalreport
[ "${status}" -eq 0 ]
grep -q ":broken_heart:" "${GITHUB_STEP_SUMMARY}"
grep -q -- "-1 overall" "${GITHUB_STEP_SUMMARY}"
grep -q "unit" "${GITHUB_STEP_SUMMARY}"
}

@test "githubactions_finalreport (with headers)" {
setup_gha
RESULT=0
TP_HEADER=("Build completed successfully")
TP_VOTE_TABLE=("|+1| compile |60||passed|")
run githubactions_finalreport
[ "${status}" -eq 0 ]
grep -q "Build completed successfully" "${GITHUB_STEP_SUMMARY}"
}

@test "githubactions_finalreport (with failed tests)" {
setup_gha
RESULT=1
TP_VOTE_TABLE=("|-1| unit |120||tests failed|")
TP_TEST_TABLE=("| Failed tests | org.example.TestFoo |")
run githubactions_finalreport
[ "${status}" -eq 0 ]
grep -q "Failed Tests" "${GITHUB_STEP_SUMMARY}"
grep -q "TestFoo" "${GITHUB_STEP_SUMMARY}"
}

@test "githubactions_finalreport (vote table header row)" {
setup_gha
RESULT=0
TP_VOTE_TABLE=("|H||||Prechecks|")
run githubactions_finalreport
[ "${status}" -eq 0 ]
grep -q "_Prechecks_" "${GITHUB_STEP_SUMMARY}"
}

@test "githubactions_finalreport (emoji vote enabled)" {
setup_gha
RESULT=0
GITHUB_USE_EMOJI_VOTE=true
TP_VOTE_TABLE=("|+1| compile |60||passed|")
run githubactions_finalreport
[ "${status}" -eq 0 ]
grep -q ":green_heart:" "${GITHUB_STEP_SUMMARY}"
}

@test "githubactions_finalreport (emoji vote disabled)" {
setup_gha
RESULT=0
GITHUB_USE_EMOJI_VOTE=false
TP_VOTE_TABLE=("|+1| compile |60||passed|")
run githubactions_finalreport
[ "${status}" -eq 0 ]
# Should have +1 but not the emoji
grep -q "+1" "${GITHUB_STEP_SUMMARY}"
! grep -q ":green_heart:" "${GITHUB_STEP_SUMMARY}"
}

setup_docker_support() {
# Source the githubactions robot
# shellcheck disable=SC1090
. "${BATS_TEST_DIRNAME}/../../main/shell/robots.d/githubactions.sh"

# Mock add_docker_env
DOCKER_EXTRAENVS=()
add_docker_env() {
for k in "$@"; do
DOCKER_EXTRAENVS+=("${k}")
done
}

DOCKER_EXTRAARGS=()
DOCKER_WORK_DIR="/workdir"
}

@test "githubactions_docker_support (no GITHUB_STEP_SUMMARY)" {
setup_docker_support
unset GITHUB_STEP_SUMMARY
run githubactions_docker_support
[ "${status}" -eq 0 ]
[ "${#DOCKER_EXTRAARGS[@]}" -eq 0 ]
}

@test "githubactions_docker_support (GITHUB_STEP_SUMMARY file missing)" {
setup_docker_support
GITHUB_STEP_SUMMARY="/nonexistent/path/summary.md"
run githubactions_docker_support
[ "${status}" -eq 0 ]
[ "${#DOCKER_EXTRAARGS[@]}" -eq 0 ]
}

@test "githubactions_docker_support (mounts summary file)" {
setup_docker_support
GITHUB_STEP_SUMMARY="${TMP}/step_summary.md"
touch "${GITHUB_STEP_SUMMARY}"
githubactions_docker_support
[[ "${DOCKER_EXTRAARGS[*]}" == *"-v"* ]]
[[ "${DOCKER_EXTRAARGS[*]}" == *"${TMP}/step_summary.md:/workdir/step_summary.md"* ]]
[ "${GITHUB_STEP_SUMMARY}" = "/workdir/step_summary.md" ]
[[ "${DOCKER_EXTRAENVS[*]}" == *"GITHUB_STEP_SUMMARY"* ]]
}
Loading