diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 569aeb8..a167c1b 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -189,12 +189,12 @@ jobs: echo "❌ ${FAILURE:-The read-back stopped on an error, see the log of this step}" if [ -n "${TOTAL:-}" ]; then echo - echo "| read back through \`$CONNECT_HOST\` | arrived | expected |" - echo "|---|---|---|" - echo "| rows | $TOTAL | 20 |" - echo "| level error | $ERRORS | 5 |" - echo "| level info | $INFOS | 15 |" - echo "| lambda name \`$FUNCTION_NAME\` | $NAMED | 20 |" + echo "Read back through \`$CONNECT_HOST\`:" + echo + echo "- rows: $TOTAL of 20" + echo "- level error: $ERRORS of 5" + echo "- level info: $INFOS of 15" + echo "- lambda name \`$FUNCTION_NAME\`: $NAMED of 20" fi [ -z "${PROBLEMS:-}" ] || { echo; echo '```'; head -20 <<<"$PROBLEMS"; echo '```'; } } > out/summary.md @@ -309,18 +309,19 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | - mkdir -p report if [ -f out/summary.md ]; then - cp out/summary.md report/summary.md + cat out/summary.md >> "$GITHUB_STEP_SUMMARY" + # The Linear issue names the job and links the run, so it gets the summary without its heading, and the + # cleanup only when that left something behind. Without a summary it gets the job's errors instead. + mkdir -p report + tail -n +3 out/summary.md > report/summary.md + grep -q '❌' out/cleanup.md 2>/dev/null && { echo; cat out/cleanup.md; } >> report/summary.md else # The read-back writes the summary however it ends, so a step before it failed (or the job was cancelled). FAILED_STEP=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/attempts/$GITHUB_RUN_ATTEMPT/jobs" \ --jq ".jobs[] | select(.runner_name == \"$RUNNER_NAME\") | .steps[] | select(.conclusion == \"failure\") | .name" | head -1) || true - { echo "### AWS CloudWatch Lambda E2E \`$RUN_ID\`"; echo; echo "❌ Stopped${FAILED_STEP:+ at **$FAILED_STEP**}, before anything was read back."; } > report/summary.md + { echo "### AWS CloudWatch Lambda E2E \`$RUN_ID\`"; echo; echo "❌ Stopped${FAILED_STEP:+ at **$FAILED_STEP**}, before anything was read back."; } >> "$GITHUB_STEP_SUMMARY" fi - cat report/summary.md >> "$GITHUB_STEP_SUMMARY" - # The Linear issue gets the cleanup only when it left something behind. - grep -q '❌' out/cleanup.md 2>/dev/null && { echo; cat out/cleanup.md; } >> report/summary.md # Rows come back as JSONEachRow with the stored event as a JSON string in raw; render them as a pretty array. [ -f out/sample_log.json ] && { echo; echo '
sample_log.json'; echo; echo '```json'; jq -s 'map(if has("raw") then .raw |= (fromjson? // .) else . end)' out/sample_log.json; echo '```'; echo '
'; echo; } >> "$GITHUB_STEP_SUMMARY" [ -f out/cleanup.md ] && { echo; cat out/cleanup.md; } >> "$GITHUB_STEP_SUMMARY" @@ -332,6 +333,7 @@ jobs: with: name: e2e-summary-CloudWatch round trip path: report/summary.md + if-no-files-found: ignore retention-days: 7 overwrite: true diff --git a/.github/workflows/notify_linear_failure.yml b/.github/workflows/notify_linear_failure.yml index 72f9f2d..4d0e962 100644 --- a/.github/workflows/notify_linear_failure.yml +++ b/.github/workflows/notify_linear_failure.yml @@ -10,8 +10,8 @@ on: default: "" job_summaries: description: >- - Adds each failed job's errors and summary to the issue. A job hands its summary over as an artifact named - "e2e-summary-" holding summary.md. + Adds each failed job's summary to the issue, or its errors when it has none. A job hands its summary over as + an artifact named "e2e-summary-" holding summary.md. type: boolean default: false @@ -49,14 +49,18 @@ jobs: FAILED="$FAILED- **$NAME** — failed at _${STEPS}_"$'\n' continue fi - # The job's ::error:: lines, without the runner's closing "Process completed with exit code 1." - ERRORS=$(gh api "repos/${{ github.repository }}/check-runs/$(jq -r .id <<<"$job")/annotations" \ - --jq '.[] | select(.annotation_level == "failure" and (.message | startswith("Process completed with exit code") | not)) | "- \(.message | gsub("\n"; " "))"') || ERRORS="" - FAILED="$FAILED### $NAME"$'\n\n'"Failed at **${STEPS}**"$'\n\n'"${ERRORS:+$ERRORS$'\n\n'}" - # A job that failed before writing its summary has no artifact and gets the errors alone. + FAILED="$FAILED### $NAME"$'\n\n'"Failed at **${STEPS}**"$'\n\n' + # A job's summary already says why it failed; a job without one (it stopped before writing it) gets its + # ::error:: lines instead, without the runner's closing "Process completed with exit code 1." SUMMARY_DIR="summaries/$(jq -r .id <<<"$job")" gh run download "$RUN_ID" -R "${{ github.repository }}" -n "e2e-summary-$NAME" -D "$SUMMARY_DIR" >/dev/null 2>&1 || true - [ ! -f "$SUMMARY_DIR/summary.md" ] || FAILED="$FAILED$(cat "$SUMMARY_DIR/summary.md")"$'\n\n' + if [ -f "$SUMMARY_DIR/summary.md" ]; then + FAILED="$FAILED$(cat "$SUMMARY_DIR/summary.md")"$'\n\n' + else + ERRORS=$(gh api "repos/${{ github.repository }}/check-runs/$(jq -r .id <<<"$job")/annotations" \ + --jq '[.[] | select(.annotation_level == "failure" and (.message | startswith("Process completed with exit code") | not)) | .message | gsub("\n"; " ")] | unique | .[] | "- \(.)"') || ERRORS="" + FAILED="$FAILED${ERRORS:+$ERRORS$'\n\n'}" + fi done <<<"$JOBS" while [[ "$FAILED" == *$'\n' ]]; do FAILED="${FAILED%$'\n'}"; done