#!/usr/bin/env bash # Copyright The containerd Authors. # Licensed 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. # Publishes the report generated by flaky-report.sh to *the* flaky test dashboard issue. # # The dashboard lives in one issue, created by hand once and named by its number: the description # is rewritten with the latest report, and a one-line digest is posted as a comment, so that the # subscribers get notified without the issue growing a full copy of every report. Nothing here # ever opens an issue, which is the point: there is exactly one, and it is the one you named. # # The URL of the issue is printed on stdout; everything else goes to stderr. # # Usage: # ./flaky-issue.sh [digest.txt] # # Environment: # SOIGNEUR_REPO repository to publish to (default: $GITHUB_REPOSITORY) # SOIGNEUR_PUBLISH set to false to do nothing at all (default: true) # SOIGNEUR_ISSUE_NUMBER the dashboard issue, as a number (required) # SOIGNEUR_ISSUE_COMMENT whether to post the digest as a comment (default: true) set -o errexit -o errtrace -o functrace -o nounset -o pipefail root="$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)" readonly root # shellcheck source-path=SCRIPTDIR . "$root"/lib.sh : "${SOIGNEUR_REPO:=${GITHUB_REPOSITORY:-}}" : "${SOIGNEUR_PUBLISH:=true}" : "${SOIGNEUR_ISSUE_NUMBER:=}" : "${SOIGNEUR_ISSUE_COMMENT:=true}" # An issue description cannot exceed 65536 characters. readonly max_body=64000 soigneur::main(){ local report="$1" local digest="${2:-}" local body number state url [ -s "$report" ] || { echo "error: empty report: $report" >&2 return 1 } soigneur::bool "$SOIGNEUR_PUBLISH" || { echo "Publishing is disabled (SOIGNEUR_PUBLISH=$SOIGNEUR_PUBLISH)" >&2 return } [ "$SOIGNEUR_REPO" != "" ] || { echo "error: no repository to publish to: set SOIGNEUR_REPO or GITHUB_REPOSITORY" >&2 return 1 } [ "$SOIGNEUR_ISSUE_NUMBER" != "" ] || { echo "error: no dashboard issue: open one by hand, then set SOIGNEUR_ISSUE_NUMBER" >&2 return 1 } soigneur::number "SOIGNEUR_ISSUE_NUMBER" "$SOIGNEUR_ISSUE_NUMBER" number="$SOIGNEUR_ISSUE_NUMBER" body="$report" if [ "$(wc -c < "$report")" -gt "$max_body" ]; then body="$(mktemp)" # shellcheck disable=SC2064 trap "rm -f '$body'" EXIT # Copy whole lines, while they fit: a byte-exact cut would leave a broken table row, and # could split a multi-byte character in half, which the API rejects. # In the C locale, awk counts bytes rather than characters, which is what the limit is in. LC_ALL=C awk -v max="$max_body" '{ total += length($0) + 1; if (total > max) exit; print }' \ "$report" > "$body" # A report whose very first line exceeds the limit cannot happen with this renderer, but # publishing an empty body would wipe the description, so that case keeps the raw cut. [ -s "$body" ] || head -c "$max_body" "$report" > "$body" printf "\n\n_Report truncated: see the workflow run for the full version._\n" >> "$body" fi gh issue edit "$number" --repo "$SOIGNEUR_REPO" --body-file "$body" > /dev/null url="https://github.com/$SOIGNEUR_REPO/issues/$number" echo "Updated $url" >&2 state="$(gh issue view "$number" --repo "$SOIGNEUR_REPO" --json state --jq '.state')" [ "$state" != "CLOSED" ] || echo "warning: the dashboard issue is closed: $url" >&2 if [ "$digest" != "" ] && [ -s "$digest" ] && soigneur::bool "$SOIGNEUR_ISSUE_COMMENT"; then gh issue comment "$number" --repo "$SOIGNEUR_REPO" \ --body "$(cat "$digest") The description above holds the full report." > /dev/null echo "Commented on $url" >&2 fi echo "$url" } # Sourcing this script defines its functions and runs nothing: that is how test.sh reaches them. [ "${BASH_SOURCE[0]}" == "${0}" ] || return 0 [ "$#" -ge 1 ] || { echo "usage: $0 [digest.txt]" >&2 exit 1 } soigneur::main "$@"