Files
openobserve/scripts/test-assist-ci-batch.sh
T
Neha PandClaude Opus 4.7 f5ee084651 ci(test-assist): batch dispatcher + qa-reports backlog sweep (#12963)
Follow-up tooling to
[#12946](https://github.com/openobserve/openobserve/pull/12946). Pairs
with the [ENT MCP-fixes
PR](https://github.com/openobserve/o2-enterprise/pull/2072) to complete
the loop from "engine works on one issue" → "batch of 100 fires in
parallel and lands verdicts in a reviewable table."

## Summary

- **`scripts/test-assist-ci-batch.sh`** — POSIX bash script that
dispatches the test-assist engine (in o2-enterprise) for a list of OSS
issues. Reads issue numbers from stdin or positional args. Supports
`--dry-run`, `--write-mode`, `--throttle`. Uses `gh workflow run` under
the maintainer's local `gh auth`. Each dispatch is fire-and-forget; the
engine's own concurrency group (`source_repo+issue`) enforces
one-run-per-issue-at-a-time.
- **`qa-reports/test-assist-ci-backlog-sweep.md`** — Roll-up table where
verdicts land after each batch. Documents the tier structure of the
priority-100 list, the verdict-to-action map (FIXED / STILL_PRESENT /
INCONCLUSIVE / SKIP), and the tier queries used to build the list. Table
starts empty; batches append rows.

## Usage

```bash
# One-shot: dispatch for a single issue
./scripts/test-assist-ci-batch.sh 12452

# Batch: dispatch for many issues in parallel (from stdin)
gh issue list --repo openobserve/openobserve --label "☢️ Bug" --label "Retested-Failed" --state open --limit 30 \
  --json number --jq '.[].number' \
  | ./scripts/test-assist-ci-batch.sh

# Dry-run to see what would fire (no dispatches)
./scripts/test-assist-ci-batch.sh --dry-run 12452 11700 12647

# Explicitly enable label+comment writes (only after soak calibration)
./scripts/test-assist-ci-batch.sh --write-mode < /tmp/batch.txt
```

## Interaction with the `Test-Assist-CI-Verified` label

The ENT engine ([PR
#2072](https://github.com/openobserve/o2-enterprise/pull/2072)) applies
the `Test-Assist-CI-Verified` label to each processed issue as factual
metadata (independent of `write_mode`). After a batch:

- [Filter checked
issues](https://github.com/openobserve/openobserve/issues?q=is%3Aissue+label%3A%22Test-Assist-CI-Verified%22)
→ the ones we've processed
- [Filter unchecked
issues](https://github.com/openobserve/openobserve/issues?q=is%3Aissue+is%3Aopen+label%3A%22%E2%98%A2%EF%B8%8F+Bug%22+-label%3A%22Test-Assist-CI-Verified%22)
→ the untouched backlog

## Test plan
- [ ] `bash -n scripts/test-assist-ci-batch.sh` — script parses
(verified locally)
- [ ] `./scripts/test-assist-ci-batch.sh --dry-run 12452` — prints "DRY:
would dispatch #12452"
- [ ] After ENT PR #2072 merges: fire a single-issue dispatch via the
script → confirm run appears in o2-enterprise Actions
- [ ] Fire the 100-issue batch → confirm verdicts populate the sweep
markdown

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-01 07:27:49 +00:00

167 lines
5.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# scripts/test-assist-ci-batch.sh — batch dispatcher for the Test-Assist CI engine.
#
# Fires the `test-assist.yml` engine (in o2-enterprise) in parallel for a list of OSS issues.
# Each engine run is its own concurrency group (keyed on source_repo+issue), so GitHub Actions
# runs them in parallel up to the runner cap.
#
# Usage:
# ./scripts/test-assist-ci-batch.sh < issue-numbers.txt # one number per line (stdin)
# ./scripts/test-assist-ci-batch.sh 12452 11700 12647 # positional args
# echo "12452 11700 12647" | tr ' ' '\n' | ./scripts/test-assist-ci-batch.sh
#
# Requires: `gh` authenticated with a token that has Actions:write on openobserve/o2-enterprise
# (typically the maintainer's PAT — `gh auth login` interactively works).
#
# Options:
# --repo-engine REPO Override the engine repo (default: openobserve/o2-enterprise).
# Restricted to an allowlist to prevent redirecting dispatches.
# --source-repo NAME Override the source repo short name (default: openobserve).
# --write-mode Set write_mode=true (default: false — no GitHub verdict writes).
# --max-parallel N Cap concurrent dispatches (default: 20). Waits when at cap.
# --throttle SECS Sleep between dispatches (default: 2). Reduces API burst.
# --dry-run Print what would be dispatched; don't call gh.
#
set -euo pipefail
REPO_ENGINE="openobserve/o2-enterprise"
SOURCE_REPO="openobserve"
WORKFLOW="test-assist.yml"
WRITE_MODE="false"
THROTTLE="2"
MAX_PARALLEL="20"
DRY_RUN=""
# Allowlist of accepted engine-repos. Prevents an accidental (or malicious) override from
# redirecting maintainer-PAT dispatches to an unrelated repo.
ALLOWED_ENGINES=("openobserve/o2-enterprise")
is_allowed_engine() {
local candidate="$1"
for e in "${ALLOWED_ENGINES[@]}"; do
[ "$candidate" = "$e" ] && return 0
done
return 1
}
# Parse flags.
args=()
while [ $# -gt 0 ]; do
case "$1" in
--repo-engine) REPO_ENGINE="$2"; shift 2;;
--source-repo) SOURCE_REPO="$2"; shift 2;;
--write-mode) WRITE_MODE="true"; shift;;
--max-parallel) MAX_PARALLEL="$2"; shift 2;;
--throttle) THROTTLE="$2"; shift 2;;
--dry-run) DRY_RUN="1"; shift;;
-h|--help) grep -E '^# ' "$0" | sed 's/^# //'; exit 0;;
*) args+=("$1"); shift;;
esac
done
# Validate the engine target BEFORE reading any input.
if ! is_allowed_engine "$REPO_ENGINE"; then
echo "::error::--repo-engine \"$REPO_ENGINE\" is not in the allowlist (${ALLOWED_ENGINES[*]})" >&2
echo "::error::Extend ALLOWED_ENGINES in this script if you need a new target." >&2
exit 1
fi
# Read issue list from positional args, or stdin if no args.
if [ "${#args[@]}" -eq 0 ]; then
mapfile -t NUMS < <(grep -E '^[0-9]+$')
else
NUMS=("${args[@]}")
fi
[ "${#NUMS[@]}" -gt 0 ] || { echo "::error::no issue numbers provided" >&2; exit 1; }
echo "==========================================="
echo "Test-Assist CI — batch dispatch"
echo " engine: $REPO_ENGINE (workflow: $WORKFLOW)"
echo " source: $SOURCE_REPO"
echo " count: ${#NUMS[@]}"
echo " max_parallel: $MAX_PARALLEL"
echo " throttle: ${THROTTLE}s"
echo " write_mode: $WRITE_MODE"
[ -n "$DRY_RUN" ] && echo " (DRY RUN — no dispatches)"
echo "==========================================="
# Pre-flight: verify gh auth works and can hit the workflow.
if [ -z "$DRY_RUN" ]; then
gh workflow view "$WORKFLOW" --repo "$REPO_ENGINE" >/dev/null 2>&1 \
|| { echo "::error::cannot access workflow $WORKFLOW on $REPO_ENGINE — check gh auth + PAT scopes"; exit 1; }
fi
# Track results properly (previous version silently swallowed backgrounded failures).
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
PID_TO_ISSUE="$TMPDIR/pid-to-issue"
: > "$PID_TO_ISSUE"
DISPATCHED=0
FAILED=0
SKIPPED=0
ACTIVE=0
for N in "${NUMS[@]}"; do
if ! [[ "$N" =~ ^[0-9]+$ ]]; then
echo " skip non-numeric: $N" >&2
SKIPPED=$(( SKIPPED + 1 ))
continue
fi
# Bounded parallelism: wait for a slot before firing the next dispatch.
while [ "$ACTIVE" -ge "$MAX_PARALLEL" ]; do
wait -n
ACTIVE=$(( ACTIVE - 1 ))
done
if [ -n "$DRY_RUN" ]; then
echo " DRY: would dispatch #$N"
DISPATCHED=$(( DISPATCHED + 1 ))
continue
fi
echo " dispatch #$N"
gh workflow run "$WORKFLOW" \
--repo "$REPO_ENGINE" \
--ref main \
-f source_repo="$SOURCE_REPO" \
-f issue_number="$N" \
-f fixture_mode=false \
-f write_mode="$WRITE_MODE" \
>/dev/null 2>>"$TMPDIR/errors.log" &
echo "$! $N" >> "$PID_TO_ISSUE"
ACTIVE=$(( ACTIVE + 1 ))
sleep "$THROTTLE"
done
# Wait for the remaining background jobs, tallying failures.
while read -r pid issue; do
if ! wait "$pid" 2>/dev/null; then
echo " FAILED: dispatch for #$issue" >&2
FAILED=$(( FAILED + 1 ))
else
DISPATCHED=$(( DISPATCHED + 1 ))
fi
done < "$PID_TO_ISSUE"
echo ""
echo "==========================================="
echo "Done."
echo " Dispatched: $DISPATCHED"
echo " Failed: $FAILED"
echo " Skipped: $SKIPPED (non-numeric input)"
if [ "$FAILED" -gt 0 ]; then
echo ""
echo "See errors:"
head -30 "$TMPDIR/errors.log" 2>/dev/null || true
fi
echo ""
echo "Track progress:"
echo " https://github.com/${REPO_ENGINE}/actions/workflows/${WORKFLOW}"
echo "==========================================="
# Non-zero exit if any dispatches failed — lets CI-invoked callers detect.
[ "$FAILED" -eq 0 ]