diff --git a/plugins/microshift-ci/scripts/check-jira-pr-links.sh b/plugins/microshift-ci/scripts/check-jira-pr-links.sh deleted file mode 100755 index cdb03fda..00000000 --- a/plugins/microshift-ci/scripts/check-jira-pr-links.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/bash -set -euo pipefail - -# Check if a JIRA issue has a GitHub PR linked. -# -# Searches GitHub via gh CLI for PRs whose title contains the JIRA key -# in the openshift/microshift repo. Checks both open and merged PRs. -# CLOSED (unmerged) PRs do not count as a match. -# -# Usage: -# check-jira-pr-links.sh -# -# Exit codes: -# 0 — PR found (prints PR URL(s) to stdout) -# 1 — no PR found -# 2 — usage error - -usage() { - echo "Usage: $(basename "$0") " >&2 - exit 2 -} - -[[ ${#} -ne 1 ]] && usage - -JIRA_KEY="${1}" - -gh_urls=$(gh pr list --repo openshift/microshift --search "${JIRA_KEY} in:title" --state open --json url --jq '.[].url' 2>/dev/null || true) -gh_urls+=$'\n'$(gh pr list --repo openshift/microshift --search "${JIRA_KEY} in:title" --state merged --json url --jq '.[].url' 2>/dev/null || true) -gh_urls=$(echo "${gh_urls}" | sed '/^$/d') -if [[ -n "${gh_urls}" ]]; then - echo "${gh_urls}" - exit 0 -fi - -exit 1 diff --git a/plugins/microshift-ci/scripts/fix-test-bugs.sh b/plugins/microshift-ci/scripts/fix-test-bugs.sh index b5d90db4..90780ee3 100755 --- a/plugins/microshift-ci/scripts/fix-test-bugs.sh +++ b/plugins/microshift-ci/scripts/fix-test-bugs.sh @@ -3,7 +3,10 @@ set -euo pipefail # Deterministic git/GitHub operations for the fix-test-bugs skill. # -# Three subcommands called by the skill with LLM steps in between: +# Subcommands called by the skill with LLM steps in between: +# +# fix-test-bugs.sh check --jira-keys KEY1,KEY2,... +# - Batch check for existing PRs across multiple JIRA keys (JSON output) # # fix-test-bugs.sh clone --workdir DIR # - Clones openshift/microshift into DIR/microshift/ @@ -50,6 +53,55 @@ cleanup_stale_branches() { done <<< "${remote_branches}" } +# --------------------------------------------------------------------------- +# check — batch PR lookup for multiple JIRA keys +# --------------------------------------------------------------------------- + +cmd_check() { + local jira_keys="" + + while [[ ${#} -gt 0 ]]; do + case "${1}" in + --jira-keys) + [[ ${#} -ge 2 && "${2}" != -* ]] || { echo "Error: --jira-keys requires a value" >&2; return 1; } + jira_keys="${2}"; shift 2 ;; + -*) echo "Unknown option: ${1}" >&2; return 1 ;; + *) echo "Unknown argument: ${1}" >&2; return 1 ;; + esac + done + + [[ -z "${jira_keys}" ]] && { echo "Error: --jira-keys is required" >&2; return 1; } + + local result="{}" + local key + + IFS=',' read -ra keys <<< "${jira_keys^^}" + for key in "${keys[@]}"; do + [[ "${key}" =~ ^[A-Z][A-Z0-9]+-[0-9]+$ ]] || { echo "Error: invalid key: ${key}" >&2; return 1; } + local prs="[]" + local raw_json state + + for state in open merged; do + raw_json=$(gh pr list --repo openshift/microshift \ + --search "${key} in:title" --state "${state}" \ + --json url,title 2>/dev/null) || raw_json='[]' + + # Post-filter: KEY must appear at start or after whitespace, followed + # by ":" or " " to avoid substring matches (e.g. USHIFT-123 matching + # USHIFT-1234) while catching multi-key and [release-X.Y] titles. + local filtered + filtered=$(echo "${raw_json}" | jq --arg key "${key}" --arg state "${state}" \ + '[.[] | select(.title | test("(^|\\s)" + $key + "[: ]")) | {url, state: $state}]') + + prs=$(echo "${prs}" "${filtered}" | jq -s '.[0] + .[1]') + done + + result=$(echo "${result}" | jq --arg key "${key}" --argjson prs "${prs}" '. + {($key): $prs}') + done + + echo "${result}" +} + # --------------------------------------------------------------------------- # clone # --------------------------------------------------------------------------- @@ -251,9 +303,11 @@ usage() { Usage: $(basename "$0") [options] Commands: - clone --workdir DIR Clone openshift/microshift and set up remotes - branch --workdir DIR --jira-key KEY Create branch from upstream/main - submit --workdir DIR --jira-key KEY --summary TXT --rationale TXT Verify, commit, push, and create PR + check --jira-keys KEY1,KEY2,... Batch check for existing PRs (JSON output) + clone --workdir DIR Clone openshift/microshift and set up remotes + branch --workdir DIR --jira-key KEY Create branch from upstream/main + submit --workdir DIR --jira-key KEY + --summary TXT --rationale TXT Verify, commit, push, and create PR EOF exit 1 } @@ -267,6 +321,7 @@ main() { shift case "${cmd}" in + check) cmd_check "${@}" ;; clone) cmd_clone "${@}" ;; branch) cmd_branch "${@}" ;; submit) cmd_submit "${@}" ;; diff --git a/plugins/microshift-ci/skills/fix-test-bugs/SKILL.md b/plugins/microshift-ci/skills/fix-test-bugs/SKILL.md index 639019b6..6b220828 100644 --- a/plugins/microshift-ci/skills/fix-test-bugs/SKILL.md +++ b/plugins/microshift-ci/skills/fix-test-bugs/SKILL.md @@ -55,7 +55,7 @@ Evaluated in order per bug. Must pass all gates to be eligible. | Gate | Check | Skip Reason | |------|-------|-------------| -| 1. Existing PR | Run `bash plugins/microshift-ci/scripts/check-jira-pr-links.sh `. The script searches GitHub for open or merged PRs whose title contains the JIRA key. Skip if it exits 0 (prints PR URL). CLOSED (unmerged) PRs do not block. | PR already exists | +| 1. Existing PR | Checked in batch before the per-bug loop (see Step 1). Skip if the key's array is non-empty (any open or merged PR). CLOSED (unmerged) PRs do not block. | PR already \: \ (e.g., "PR already merged: https://...") | | 2. In-scope files | Scan bug description for file paths in `test/`, `scripts/`, `docs/`. Also resolve bare filenames to their directory (e.g., `el98@rpm-standard1.sh` -> `test/scenarios/`, `configure-pri.sh` -> `scripts/multinode/`). Skip if ALL referenced files are outside the allowed directories (e.g., only `cmd/`, `pkg/`, `vendor/`). | Fix target outside allowed dirs | | 3. Root cause is code-fixable | Skip if root cause indicates: product bug in MicroShift core (not test/script issue), transient environmental issue, or upstream dependency problem with no local workaround. Pass if root cause points to: test logic, timeout, configuration, assertion, variable resolution, checksum, script error handling, or documentation. | Not code-fixable | @@ -92,7 +92,15 @@ Evaluated in order per bug. Must pass all gates to be eligible. ``` 4. For each issue in the search results, **immediately** save the complete response to `/fix-test-bugs/bug-.json`. The saved JSON must contain all fields returned — at minimum: `key`, `summary`, `description` (the full bug description text), `status`, `priority`, `assignee`, `labels`, `created`, and `updated`. Write the complete response — do not summarize or omit fields. -5. Apply Gates 1-3 to each bug and record status: `eligible` or `skipped` (with gate and reason) +5. **Batch PR check** (Gate 1 for all bugs at once): Run a single call with all keys: + + ```text + bash plugins/microshift-ci/scripts/fix-test-bugs.sh check --jira-keys KEY1,KEY2,... + ``` + + Returns JSON: `{"KEY1": [{"url": "...", "state": "open|merged"}, ...], "KEY2": []}`. A non-empty array means a PR exists — skip that bug. Use the url and state from the result in the skip reason (e.g., "PR already merged: https://..."). + +6. Apply Gates 2-3 to remaining bugs and record status: `eligible` or `skipped` (with gate and reason) ### Step 2: Present Dry-Run Report