diff --git a/.github/scripts/o2-report.sh b/.github/scripts/o2-report.sh index 70cc4f8e1e..19a372c3bc 100755 --- a/.github/scripts/o2-report.sh +++ b/.github/scripts/o2-report.sh @@ -33,14 +33,19 @@ if [ ! -s "$PAYLOAD" ]; then exit 0 fi -# OpenObserve's _json endpoint accepts a single object or an array; wrap to an array. # Stream the body from a temp file (mktemp → unique per invocation, no shared-/tmp races, # no whole-payload-in-a-shell-var). URL="${O2_REPORTING_INGEST_BASE%/}/${STREAM}/_json" BODY_FILE=$(mktemp "${TMPDIR:-/tmp}/o2_report_body.XXXXXX") RESP_FILE=$(mktemp "${TMPDIR:-/tmp}/o2_report_resp.XXXXXX") trap 'rm -f "$BODY_FILE" "$RESP_FILE"' EXIT -{ printf '['; cat "$PAYLOAD"; printf ']'; } > "$BODY_FILE" +# _json accepts a single object OR an array. Wrap a bare object in [ ]; pass an existing array +# through unchanged so multi-row callers (e.g. per-shard rows) aren't double-wrapped into [[...]]. +if [ "$(tr -d '[:space:]' < "$PAYLOAD" | cut -c1)" = "[" ]; then + cat "$PAYLOAD" > "$BODY_FILE" +else + { printf '['; cat "$PAYLOAD"; printf ']'; } > "$BODY_FILE" +fi INSECURE="" [ "${O2_REPORTING_INSECURE:-}" = "true" ] && INSECURE="-k" diff --git a/.github/scripts/o2-run-report.sh b/.github/scripts/o2-run-report.sh index 17f511d166..464a65cdf1 100755 --- a/.github/scripts/o2-run-report.sh +++ b/.github/scripts/o2-run-report.sh @@ -107,3 +107,22 @@ if [ -n "${EXTRA_JSON:-}" ] && printf '%s' "$EXTRA_JSON" | jq -e . >/dev/null 2> fi bash "$(dirname "$0")/o2-report.sh" "$STREAM" "$PAYLOAD_FILE" + +# For runs with e2e shard jobs (UI), also emit one row per shard to _shards so dashboards +# can break down per-shard duration / slowest shard / per-module health (mirrors ci_regression_shards). +# API runs have no "e2e /" jobs, so this is a no-op there. Row schema: +# run_id, repo, suite, workflow, ingest_source, shard_name, module (shard minus "e2e / "), +# conclusion, duration_sec. _timestamp left unset -> ingest time (aligned with the run doc). +# Notes: THIS_JOBS is the jobs API object {jobs:[...]}, piped in (so .jobs[]); workflow:"test" is +# fixed to match the run doc's tag; duration clamped to >=0 to guard against runner clock skew. +SHARD_FILE=$(mktemp "${TMPDIR:-/tmp}/o2_shards.XXXXXX") +shard_rows=$(printf '%s' "$THIS_JOBS" | jq -c --arg repo "$GITHUB_REPOSITORY" --arg run_id "$GITHUB_RUN_ID" --arg suite "$SUITE" \ + '[.jobs[]? | select(.name|startswith("e2e /")) | { + run_id:$run_id, repo:$repo, suite:$suite, workflow:"test", ingest_source:"live", + shard_name:.name, module:(.name|sub("^e2e / ";"")), conclusion:.conclusion, + duration_sec: (if (.completed_at and .started_at) then ([((.completed_at|fromdateiso8601)-(.started_at|fromdateiso8601)|floor), 0] | max) else null end) + }]' 2>/dev/null) && printf '%s' "$shard_rows" > "$SHARD_FILE" || { echo '[]' > "$SHARD_FILE"; echo "::warning::shard-row extraction failed — skipping ${STREAM}_shards"; } +if [ "$(jq 'length' "$SHARD_FILE" 2>/dev/null || echo 0)" -gt 0 ]; then + bash "$(dirname "$0")/o2-report.sh" "${STREAM}_shards" "$SHARD_FILE" +fi +rm -f "$SHARD_FILE"