Skip to content

feat(jira): add candidates-from-pr command#451

Open
qinqon wants to merge 3 commits into
openshift-eng:mainfrom
qinqon:feat/jira-candidates-from-pr
Open

feat(jira): add candidates-from-pr command#451
qinqon wants to merge 3 commits into
openshift-eng:mainfrom
qinqon:feat/jira-candidates-from-pr

Conversation

@qinqon
Copy link
Copy Markdown

@qinqon qinqon commented May 7, 2026

What this PR does / why we need it:

Adds /jira:candidates-from-pr, a read-only triage helper that takes a GitHub PR and surfaces a ranked list of open Jira issues the PR may fix, scoped by component and target release. It is the inverse direction of /jira:extract-prs (which goes Jira → PRs).

The command:

  1. Fetches PR title, body, commits, files, and diff via gh pr view / gh pr diff.
  2. Extracts already-referenced Jira keys from the PR title/body/commits/branch and validates them via the Jira MCP — these are reported separately as explicit references, not re-scored as candidates (unless --include-explicit is passed).
  3. Derives component(s) from the repo and changed file paths (with --component override) and target release from the PR's base branch (with --target-release override). For OCPBUGS the user-facing Target Version (customfield_10855) is preferred over fixVersions — see plugins/jira/reference/mcp-tools.md:295.
  4. Builds a JQL filtered by project, component, target release / fix version, and statusCategory != Done, and runs mcp__atlassian__jira_search.
  5. Locally scores each candidate (no per-candidate API calls) by error-string, symbol, keyword, component, and recency overlap against the PR diff. Each candidate ships with a 1-2 sentence rationale and the matched signals.
  6. Outputs either a human-readable report or --output json for downstream tooling.

The command is read-only — it never posts comments, links the PR, or modifies Jira state. It is intended to assist maintainer triage when a PR was opened without a clear Jira reference (or with an incomplete one), e.g. on openshift/ovn-kubernetes.

Files

  • plugins/jira/commands/candidates-from-pr.md — command spec (/jira:candidates-from-pr <pr-url-or-number> plus flags).
  • plugins/jira/skills/candidates-from-pr/SKILL.md — full implementation guide: phases, scoring rubric, JSON schema, error handling, performance notes.
  • plugins/jira/.claude-plugin/plugin.json — version bump 0.4.3 → 0.4.4.
  • .claude-plugin/marketplace.json, PLUGINS.md, docs/data.json — regenerated via make update.

Overlap review (per AGENTS.md)

Ran the equivalent of /utils:review-ai-helpers-overlap --idea "given a GitHub PR, find candidate open Jiras with matching target release that the PR may fix, by analyzing the diff and component" against 100 open PRs and main-branch commands.

No HIGH or MODERATE overlap found. Closest neighbors (all LOW):

Existing work Why it's different
jira:extract-prs (main) Opposite direction (Jira → PRs).
jira:reconcile-github (main) GitHub issues state-mapping via gh2jira, not PR-diff matching.
utils:process-renovate-pr (main) Creates a new Jira from a Renovate PR; doesn't match existing ones.
#420 bug-triage:scrub Starts from a team's untriaged bugs and posts triage comments; doesn't start from a PR.
#171 "Pr analyzer" Diff is empty (only autogen docs); effectively inactive.
#245 github:issue-triage Triages GitHub issues with labels; doesn't touch Jira.
#432 jira:post-summary-comment Requires the Jira key as input; doesn't discover candidates.

Validation

  • make update: ✓ marketplace and docs regenerated.
  • make lint: ✓ 0 errors, 0 warnings.

Which issue(s) this PR fixes:

Fixes

Special notes for your reviewer:

  • Component derivation uses a small built-in repo→component table for common OpenShift networking repos plus a path-based heuristic. If derivation fails, the JQL is run without a component clause and the user is warned. The table can be extended over time; --component always overrides.
  • Target Version vs. fixVersions: the JQL queries both, but reporting prefers Target Version (customfield_10855) because for OCPBUGS that's the user-facing field while fixVersions is owned by the release team.
  • Two-pass output: explicit Jira keys mentioned in the PR are reported separately and not re-scored as candidates by default. This avoids "PR mentions OCPBUGS-1234, score 100" noise. Pass --include-explicit to bypass.
  • Local scoring only: the scoring rubric is documented in the skill (plugins/jira/skills/candidates-from-pr/SKILL.md) and runs entirely on in-memory PR signals vs. the Jira fields returned by the search — no per-candidate API calls.
  • Companion to /jira:extract-prs. Naming follows existing patterns (extract-prs, clone-from-github, reconcile-github).

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.

Assisted-By: Claude noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • Added /jira:candidates-from-pr — finds, scores, and ranks open Jira issue candidates for a GitHub PR with component and target-release filtering, limit/min-score options, include-explicit flag, and text or JSON output.
  • Documentation

    • Full user guide, examples, argument/flag reference, and canonical JSON/text output schema for the new command.
  • Chores

    • Jira plugin version bumped to 0.4.8; marketplace config updated to allow official plugins.

@openshift-ci openshift-ci Bot requested review from brandisher and rvanderp3 May 7, 2026 07:50
@openshift-ci openshift-ci Bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label May 7, 2026
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 7, 2026

Hi @qinqon. Thanks for your PR.

I'm waiting for a openshift-eng member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work.

Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new Jira command/skill /jira:candidates-from-pr with documentation, a skill guide, and a set of CLI scripts (fetch_pr, derive_filters, extract_jira_keys, extract_signals, build_jql, score_candidates, render_report); bumps the Jira plugin version to 0.4.8 and adjusts marketplace allowCrossMarketplaceDependenciesOn to an array.

Changes

Jira candidates-from-pr feature + manifest updates

Layer / File(s) Summary
Marketplace & manifest
.claude-plugin/marketplace.json, plugins/jira/.claude-plugin/plugin.json, docs/data.json
allowCrossMarketplaceDependenciesOn represented as an array; Jira plugin version bumped 0.4.40.4.8 (manifest and docs).
Registry / Command registration
docs/data.json, PLUGINS.md
Registers new candidates-from-pr command for jira with argument_hint and docs entry.
User docs
plugins/jira/commands/candidates-from-pr.md
New command documentation: synopsis, examples, flags, outputs, and behavior notes.
Skill guidance / schema
plugins/jira/skills/candidates-from-pr/SKILL.md
Skill specification: orchestration rules, expected scripts, canonical JSON schema, scoring rubric, and error handling.
PR normalization / I/O
plugins/jira/skills/candidates-from-pr/scripts/fetch_pr.py
CLI resolving PR input, runs gh pr view + gh pr diff, caps/truncates diffs, records diff metadata, emits normalized PR JSON.
Filter derivation
plugins/jira/skills/candidates-from-pr/scripts/derive_filters.py
Derives components and target_release via CLI overrides, repo→component mapping, path heuristics, or branch parsing; emits JSON with sources/warnings.
Explicit Jira key extraction
plugins/jira/skills/candidates-from-pr/scripts/extract_jira_keys.py
Scans PR title/body/branch/commits for Jira-style keys, filters by projects, deduplicates, and outputs keys with sources.
Signal extraction
plugins/jira/skills/candidates-from-pr/scripts/extract_signals.py
Extracts triage signals from added diff lines (or synthetic commit text): symbols, error strings, log messages, title/commit keywords, path tags, labels, and diff availability.
JQL builder
plugins/jira/skills/candidates-from-pr/scripts/build_jql.py
Builds JQL from filters: project, statusCategory != Done, optional component in (...), optional target_release clauses; outputs ordered JQL string.
Candidate scoring
plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py
Locally scores Jira candidates against extracted signals with weights, recency bonus, penalties/drops, verdict thresholds; outputs ranked JSON (--limit, --min-score).
Report rendering
plugins/jira/skills/candidates-from-pr/scripts/render_report.py
Renders human-readable text report or canonical JSON payload combining PR, derived filters, explicit refs, and scored candidates; supports rationales injection.
Docs/registry update
PLUGINS.md, docs/data.json
Documentation and registry updated to expose the command and skill in plugin listings.
sequenceDiagram
    participant User as User
    participant CLI as "/jira:candidates-from-pr"
    participant Fetch as "fetch_pr.py"
    participant GH as "GitHub (gh)"
    participant ExtractKeys as "extract_jira_keys.py"
    participant Derive as "derive_filters.py"
    participant Signals as "extract_signals.py"
    participant BuildJQL as "build_jql.py"
    participant Jira as "Jira (search)"
    participant Score as "score_candidates.py"
    participant Render as "render_report.py"

    User->>CLI: invoke /jira:candidates-from-pr <pr> [flags]
    CLI->>Fetch: run fetch_pr (PR JSON + diff)
    Fetch->>GH: gh pr view / gh pr diff
    Fetch-->>CLI: PR JSON + diff (capped/truncated)
    CLI->>ExtractKeys: extract explicit Jira keys (stdin PR JSON)
    CLI->>Derive: derive components/target_release (stdin PR JSON)
    CLI->>Signals: extract signals (stdin PR JSON + diff)
    Derive->>BuildJQL: produce filters -> build JQL string
    BuildJQL->>Jira: run JQL search -> candidates
    Jira-->>CLI: candidate list
    CLI->>Score: score_candidates (signals + candidates + filters)
    Score-->>CLI: ranked candidates
    CLI->>Render: render_report (pr, filters, explicit, candidates)
    Render-->>User: text|json report
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

ok-to-test

Suggested reviewers

  • enxebre
  • brandisher
  • rvanderp3

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
No Real People Names In Style References ❌ Error PR contains real person name "Jane Doe" in example JSON schemas in plugin command and skill documentation files. Replace "Jane Doe" example name with generic placeholder like "..." or describe field as <display_name>. Locations: plugins/jira/commands/candidates-from-pr.md:159 and plugins/jira/skills/candidates-from-pr/SKILL.md:65.
Docstring Coverage ⚠️ Warning Docstring coverage is 8.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(jira): add candidates-from-pr command' directly and clearly describes the main change in the PR—adding a new Jira command. It is concise, specific, and aligns with the primary objective of implementing the /jira:candidates-from-pr feature across multiple files and scripts.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Assumed Git Remote Names ✅ Passed PR contains no hardcoded git remote names. All external commands use 'gh' CLI with explicit --repo arguments rather than assuming 'origin' or 'upstream'.
Git Push Safety Rules ✅ Passed No git push operations found. The PR adds a read-only jira command that only uses gh CLI to read PR data. No force push, autonomous push, or push to main/master detected.
No Untrusted Mcp Servers ✅ Passed No untrusted MCP servers introduced. PR adds 7 Python utility scripts for local processing and references only pre-existing Atlassian Jira MCP tools already used elsewhere in the plugin.
Ai-Helpers Overlap Detection ✅ Passed No overlapping functionality detected. candidates-from-pr (PR→Jira) is inverse to extract-prs (Jira→PR). Similarity: 12% (below 60% threshold).
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/jira/commands/candidates-from-pr.md`:
- Around line 10-12: The markdown file has multiple fenced code blocks missing
language tags; update each fence to include an appropriate language (e.g., mark
the CLI example "/jira:candidates-from-pr <pr-url-or-number> [options]" as text,
the JQL query block as jql, and any shell snippets as bash or JSON examples as
json) so markdownlint MD040 warnings are cleared; locate the blocks containing
the command string and the JQL query (and the other fenced examples noted in the
review) and prepend the fence with the correct language identifier.

In `@plugins/jira/skills/candidates-from-pr/SKILL.md`:
- Around line 110-115: The Markdown has markdownlint warnings MD040/MD058: add
language tags to fenced code blocks (e.g., the mcp__atlassian__jira_get_issue
code blocks) and ensure blank lines before and after any Markdown tables to
satisfy MD058 and MD040; update all occurrences referenced (blocks around lines
showing mcp__atlassian__jira_get_issue and the ranges 124-131, 142-144, 151-157,
160-166, 223-246) by adding an appropriate language identifier (like ```bash or
```yaml) to each fenced code block and inserting blank lines above and below
each table so the document passes linting.
- Around line 141-146: The release-selection rule in SKILL.md is contradictory:
replace the "Choose the smallest version where `released == false`" instruction
with a single consistent rule to "Choose the highest unreleased numeric version"
so both bullets match; update the text around
mcp__atlassian__jira_get_project_versions(project_key=<KEY>) and the
`target_release_source` guidance to reflect this single rule (highest unreleased
numeric version) and remove the conflicting "smallest" wording.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 838048e9-b87b-485b-b2c3-25df6f4c4e7e

📥 Commits

Reviewing files that changed from the base of the PR and between d2de5a1 and 3fefac7.

📒 Files selected for processing (6)
  • .claude-plugin/marketplace.json
  • PLUGINS.md
  • docs/data.json
  • plugins/jira/.claude-plugin/plugin.json
  • plugins/jira/commands/candidates-from-pr.md
  • plugins/jira/skills/candidates-from-pr/SKILL.md

Comment thread plugins/jira/commands/candidates-from-pr.md Outdated
Comment thread plugins/jira/skills/candidates-from-pr/SKILL.md Outdated
Comment thread plugins/jira/skills/candidates-from-pr/SKILL.md Outdated
@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch 2 times, most recently from c345da7 to 9e3c5a9 Compare May 7, 2026 08:52
@qinqon qinqon marked this pull request as draft May 7, 2026 08:56
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 7, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
plugins/jira/skills/candidates-from-pr/SKILL.md (1)

89-94: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Unresolved markdownlint MD040 warnings — fenced blocks still lack language tags.

Lines 89, 109, and 123 all have fenced code blocks without a language identifier. This was flagged in a prior review and remains unfixed.

♻️ Proposed fix for the three unlabelled blocks
-```
+```text
 mcp__atlassian__jira_get_issue(
   issue_key=<KEY>,
   fields="summary,status,issuetype,components,fixVersions,customfield_10855,assignee"
 )

Apply the same `text` (or `python`) label to the blocks at lines 109 and 123.
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @plugins/jira/skills/candidates-from-pr/SKILL.md around lines 89 - 94, The
fenced code blocks containing the mcp__atlassian__jira_get_issue(...) example
(and the two other similar blocks later) lack language tags and trigger
markdownlint MD040; update each fenced block around the
mcp__atlassian__jira_get_issue snippet and the two other occurrences to use a
language label (e.g., text or python) so the fences are explicitly tagged
and the MD040 warnings are resolved, ensuring all three blocks use the same
label as suggested.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (4)</summary><blockquote>

<details>
<summary>plugins/jira/skills/candidates-from-pr/scripts/fetch_pr.py (1)</summary><blockquote>

`27-27`: _💤 Low value_

**Document Python version requirement or use `from __future__ import annotations`.**

The code uses PEP 604 union syntax (`str | None`), which is a runtime `SyntaxError` on Python 3.9. SKILL.md states "Python 3" without specifying a minimum version. The same pattern appears in other scripts (`score_candidates.py`, `gather.py`). Either update the prerequisite section to document `>= 3.10` or add `from __future__ import annotations` at the top of the file for broader compatibility.

<details>
<summary>Two options</summary>

Option 1 — document the constraint:
```diff
+# Requires Python >= 3.10 (PEP 604 union type syntax).
 def resolve_pr(arg: str, repo: str | None) -> tuple[str, str, int]:
```

Option 2 — support Python 3.9+ without a stdlib change:
```diff
+from __future__ import annotations
+
 import argparse
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/jira/skills/candidates-from-pr/scripts/fetch_pr.py` at line 27, The
function signature resolve_pr(arg: str, repo: str | None) uses PEP 604 union
syntax which raises SyntaxError on Python <3.10; either document the minimum
Python version as >=3.10 in the project prerequisites (SKILL.md) or make the
code compatible with 3.9+ by adding from __future__ import annotations at the
top of this file (and the other affected scripts score_candidates.py and
gather.py) so the union type syntax is deferred to annotations and remains valid
at runtime.
```

</details>

</blockquote></details>
<details>
<summary>plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py (3)</summary><blockquote>

`122-125`: _💤 Low value_

**Redundant condition in `elif` guard.**

Inside the `elif` branch the intersection is already known to be empty (it's the logical complement of the `if` at line 114), so `not (cand_components & derived_components)` is always `True` and adds noise.

<details>
<summary>♻️ Proposed simplification</summary>

```diff
-    elif component_filter_used and not (cand_components & derived_components):
+    elif component_filter_used:
         # JQL should have prevented this; guard anyway.
         score = 0
         return score, matched
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py` around
lines 122 - 125, The elif check redundantly tests not (cand_components &
derived_components) because that case is already the complement of the earlier
if; simplify the branch by removing the redundant set-intersection test and only
check component_filter_used (i.e., change "elif component_filter_used and not
(cand_components & derived_components):" to "elif component_filter_used:"), then
keep the body that sets score = 0 and returns score, matched so behavior is
unchanged but the condition is clearer; refer to the variables cand_components,
derived_components, component_filter_used, score, and matched to locate the
change.
```

</details>

---

`48-49`: _💤 Low value_

**`lower()` helper is dead code.**

The function is defined but never called; `find_lower` does not use it, and no other site in the file does either. Can be removed.

<details>
<summary>🧹 Proposed removal</summary>

```diff
-def lower(value: str | None) -> str:
-    return (value or "").lower()
-
-
 def load(path: str) -> object:
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py` around
lines 48 - 49, The helper function lower is unused dead code; remove the
function definition def lower(value: str | None) -> str: return (value or
"").lower() from the file and ensure no other code (e.g., find_lower or callers)
rely on it—search for symbols lower and find_lower to confirm only find_lower is
used and that removing lower is safe, then delete the unused lower function and
run tests/lint to verify no references remain.
```

</details>

---

`65-68`: _⚡ Quick win_

**`find_lower` should lowercase needles for defensive coding, but the bug doesn't manifest in practice.**

The haystack is correctly pre-lowercased, but the proposed fix is still valid as a safeguard. However, `title_values` and `path_values` are already lowercased by `extract_signals.py` before being written to `signals.json`:
- `title_keywords()` lowercases every token (line 110: `lo = t.lower()`)
- `path_tags()` lowercases every path component (line 126: `part.lower()`)

So the actual scoring impact is zero—mixed-case keywords will not "silently zero out" contributions because they never reach `find_lower()` in mixed case. The function works correctly in its current context.

That said, `find_lower()`'s design suggests intent for case-insensitive matching. Adding `.lower()` to needles remains a defensible refactor to prevent future breakage if upstream processing changes, but this is a code quality improvement rather than a bug fix.

<details>
<summary>Suggested fix (defensive coding)</summary>

```diff
 def find_lower(needles: list[str], text_lower: str) -> list[str]:
     if not needles or not text_lower:
         return []
-    return [n for n in needles if n and n in text_lower]
+    return [n for n in needles if n and n.lower() in text_lower]
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py` around
lines 65 - 68, The function find_lower currently checks membership against a
pre-lowercased haystack (text_lower) but does not defensively lowercase the
needles; update find_lower to normalize each needle by calling .lower() (while
still skipping falsy/None needles) before testing membership against text_lower
so matching remains case-insensitive even if upstream stops lowercasing
(reference: function name find_lower and its parameters needles and text_lower).
```

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In @plugins/jira/skills/candidates-from-pr/SKILL.md:

  • Around line 89-94: The fenced code blocks containing the
    mcp__atlassian__jira_get_issue(...) example (and the two other similar blocks
    later) lack language tags and trigger markdownlint MD040; update each fenced
    block around the mcp__atlassian__jira_get_issue snippet and the two other
    occurrences to use a language label (e.g., text or python) so the fences
    are explicitly tagged and the MD040 warnings are resolved, ensuring all three
    blocks use the same label as suggested.

Nitpick comments:
In @plugins/jira/skills/candidates-from-pr/scripts/fetch_pr.py:

  • Line 27: The function signature resolve_pr(arg: str, repo: str | None) uses
    PEP 604 union syntax which raises SyntaxError on Python <3.10; either document
    the minimum Python version as >=3.10 in the project prerequisites (SKILL.md) or
    make the code compatible with 3.9+ by adding from future import annotations
    at the top of this file (and the other affected scripts score_candidates.py and
    gather.py) so the union type syntax is deferred to annotations and remains valid
    at runtime.

In @plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py:

  • Around line 122-125: The elif check redundantly tests not (cand_components &
    derived_components) because that case is already the complement of the earlier
    if; simplify the branch by removing the redundant set-intersection test and only
    check component_filter_used (i.e., change "elif component_filter_used and not
    (cand_components & derived_components):" to "elif component_filter_used:"), then
    keep the body that sets score = 0 and returns score, matched so behavior is
    unchanged but the condition is clearer; refer to the variables cand_components,
    derived_components, component_filter_used, score, and matched to locate the
    change.
  • Around line 48-49: The helper function lower is unused dead code; remove the
    function definition def lower(value: str | None) -> str: return (value or
    "").lower() from the file and ensure no other code (e.g., find_lower or callers)
    rely on it—search for symbols lower and find_lower to confirm only find_lower is
    used and that removing lower is safe, then delete the unused lower function and
    run tests/lint to verify no references remain.
  • Around line 65-68: The function find_lower currently checks membership against
    a pre-lowercased haystack (text_lower) but does not defensively lowercase the
    needles; update find_lower to normalize each needle by calling .lower() (while
    still skipping falsy/None needles) before testing membership against text_lower
    so matching remains case-insensitive even if upstream stops lowercasing
    (reference: function name find_lower and its parameters needles and text_lower).

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Path: .coderabbit.yaml

**Review profile**: CHILL

**Plan**: Enterprise

**Run ID**: `e6227704-319d-467b-9a2c-e89fad1af8b0`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 3fefac76ea91dec59cc101568fd9763caf3d5579 and 9e3c5a9a56df8b8ab3ce1d62c5397cf17160d64f.

</details>

<details>
<summary>📒 Files selected for processing (13)</summary>

* `.claude-plugin/marketplace.json`
* `PLUGINS.md`
* `docs/data.json`
* `plugins/jira/.claude-plugin/plugin.json`
* `plugins/jira/commands/candidates-from-pr.md`
* `plugins/jira/skills/candidates-from-pr/SKILL.md`
* `plugins/jira/skills/candidates-from-pr/scripts/build_jql.py`
* `plugins/jira/skills/candidates-from-pr/scripts/derive_filters.py`
* `plugins/jira/skills/candidates-from-pr/scripts/extract_jira_keys.py`
* `plugins/jira/skills/candidates-from-pr/scripts/extract_signals.py`
* `plugins/jira/skills/candidates-from-pr/scripts/fetch_pr.py`
* `plugins/jira/skills/candidates-from-pr/scripts/render_report.py`
* `plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py`

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (2)</summary>

* plugins/jira/skills/candidates-from-pr/scripts/render_report.py
* plugins/jira/skills/candidates-from-pr/scripts/extract_signals.py

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* PLUGINS.md

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch from 9e3c5a9 to 50057d1 Compare May 7, 2026 09:47
@qinqon
Copy link
Copy Markdown
Author

qinqon commented May 8, 2026

Rebased commit 50057d1 on main and pushed (conflicts resolved).

@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch from 50057d1 to 1bc068a Compare May 8, 2026 13:07
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (3)
plugins/jira/skills/candidates-from-pr/SKILL.md (2)

96-96: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

MD040: fenced code blocks still lack language tags (previously flagged, not fully resolved).

Lines 96, 116, and 130 open with a bare ``` fence. The past review flagging these was marked addressed in commit 50057d1, but the warnings persist in the current state.

✏️ Proposed fix
-```
+```text
 mcp__atlassian__jira_get_issue(
-```
+```text
 mcp__atlassian__jira_get_project_versions(project_key=<KEY>)
-```
+```text
 mcp__atlassian__jira_search(

Also applies to: 116-116, 130-130

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/jira/skills/candidates-from-pr/SKILL.md` at line 96, Several fenced
code blocks in SKILL.md open with bare ``` fences (lines around the
mcp__atlassian__jira_get_issue, mcp__atlassian__jira_get_project_versions, and
mcp__atlassian__jira_search examples) and need explicit language tags; update
each opening fence to include a language (e.g., ```text) so the blocks become
```text mcp__atlassian__jira_get_issue(...), ```text
mcp__atlassian__jira_get_project_versions(project_key=<KEY>), and ```text
mcp__atlassian__jira_search(...), ensuring all three occurrences (around the
listed function names) are changed to remove the MD040 warning.

120-120: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

"smallest" version rule still contradicts the command doc (previously flagged, not resolved).

Line 120 instructs the AI to pick the "smallest version where released == false", but candidates-from-pr.md line 83 says "pick the latest unreleased version." The past review raised this exact contradiction and was marked addressed in commit 50057d1, yet the "smallest" wording persists here.

For main/master branches the intent is to find the current development release (highest unreleased version), so "smallest" produces the wrong target release.

✏️ Proposed fix
-Pick the **smallest** version where `released == false` and rewrite `filters.json` with it (set `target_release_source = "project_versions"`).
+Pick the **highest** unreleased numeric version where `released == false` and rewrite `filters.json` with it (set `target_release_source = "project_versions"`).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/jira/skills/candidates-from-pr/SKILL.md` at line 120, Replace the
contradictory phrase 'Pick the "smallest" version where `released == false`' in
SKILL.md with wording that matches the other doc: "pick the latest unreleased
version (highest/unreleased) and rewrite `filters.json` with it (set
`target_release_source = \"project_versions\"`)"; ensure the language and any
associated logic or examples explicitly state the highest unreleased version for
main/master branches (current development release) so it aligns with the
instruction in the other candidates-from-pr documentation.
plugins/jira/commands/candidates-from-pr.md (1)

10-12: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

MD040: fenced code blocks still lack language tags (previously flagged, not addressed).

Lines 10, 87, 112, 117, 122, 128, and 134 all open with bare ``` fences. This was raised in a previous review with no "addressed" resolution.

✏️ Proposed fix (representative examples)
-```
+```text
 /jira:candidates-from-pr <pr-url-or-number> [options]

```diff
-```
+```jql
 project = <KEY>
   AND statusCategory != Done

```diff
-```
+```text
 /jira:candidates-from-pr https://github.com/openshift/ovn-kubernetes/pull/4567
</details>

Apply `text` or an appropriate language identifier to each remaining bare fence block.





Also applies to: 87-93, 112-114, 117-119, 122-125, 128-131, 134-136

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @plugins/jira/commands/candidates-from-pr.md around lines 10 - 12, The
markdown file contains multiple fenced code blocks with bare fences (notably the example command `/jira:candidates-from-pr <pr-url-or-number> [options]` and JQL examples) that must include language identifiers; update each bare fence in plugins/jira/commands/candidates-from-pr.md (including the examples around the `/jira:candidates-from-pr` snippet and the JQL blocks) by adding an appropriate language tag such as `text` for CLI examples and `jql` for query blocks so every becomes text or jql as appropriate.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @plugins/jira/commands/candidates-from-pr.md:

  • Around line 151-169: The candidates schema's "assignee" is currently a string
    ("Jane Doe") but SKILL.md documents it as an object with display_name and email;
    update the candidates example/schema so "assignee" is an object (e.g., {
    "display_name": "Jane Doe", "email": "..." }) everywhere in the "candidates"
    array and any related examples (including matched_signals/explicit_references
    examples) to match the SKILL.md projection and preserve the richer assignee
    structure.

In @plugins/jira/skills/candidates-from-pr/scripts/fetch_pr.py:

  • Around line 72-77: The assignment to diff_unavailable_reason in the rc != 0
    block can raise IndexError when diff_err is all-whitespace because
    ("".strip().splitlines()[-1]) is empty; change the logic that computes
    diff_unavailable_reason (in the rc != 0 branch where diff and
    diff_unavailable_reason are set) to first pick diff_err or "unknown error",
    strip it, splitlines, then if the resulting list is empty fall back to "unknown
    error" (or use the original fallback) so you never index [-1] on an empty list.

In @plugins/jira/skills/candidates-from-pr/SKILL.md:

  • Around line 42-45: Add jq to the prerequisites list because step that runs
    COMPS=$(jq -r '.components | join(",")' filters.json) shells out to it; update
    the prerequisites block (the lines listing gh CLI, Jira MCP server, and Python
  1. to include jq (e.g., "jq (JSON processor)") so readers know it must be
    installed before running the skill.

Duplicate comments:
In @plugins/jira/commands/candidates-from-pr.md:

  • Around line 10-12: The markdown file contains multiple fenced code blocks with
    bare fences (notably the example command `/jira:candidates-from-pr <pr-url-or-number> [options]` and JQL examples) that must include language identifiers; update each bare fence in plugins/jira/commands/candidates-from-pr.md (including the examples around the `/jira:candidates-from-pr` snippet and the JQL blocks) by adding an appropriate language tag such as `text` for CLI examples and `jql` for query blocks so every becomes text or jql as appropriate.

In @plugins/jira/skills/candidates-from-pr/SKILL.md:

  • Line 96: Several fenced code blocks in SKILL.md open with bare fences (lines around the mcp__atlassian__jira_get_issue, mcp__atlassian__jira_get_project_versions, and mcp__atlassian__jira_search examples) and need explicit language tags; update each opening fence to include a language (e.g.,text) so the blocks become text mcp__atlassian__jira_get_issue(...), text
    mcp__atlassian__jira_get_project_versions(project_key=), and ```text
    mcp__atlassian__jira_search(...), ensuring all three occurrences (around the
    listed function names) are changed to remove the MD040 warning.
  • Line 120: Replace the contradictory phrase 'Pick the "smallest" version where
    released == false' in SKILL.md with wording that matches the other doc: "pick
    the latest unreleased version (highest/unreleased) and rewrite filters.json
    with it (set target_release_source = \"project_versions\")"; ensure the
    language and any associated logic or examples explicitly state the highest
    unreleased version for main/master branches (current development release) so it
    aligns with the instruction in the other candidates-from-pr documentation.

</details>

<details>
<summary>🪄 Autofix (Beta)</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Path: .coderabbit.yaml

**Review profile**: CHILL

**Plan**: Enterprise

**Run ID**: `ef6b8f63-c4bf-4c48-86cc-ecbaae82a80e`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9e3c5a9a56df8b8ab3ce1d62c5397cf17160d64f and 1bc068a5c141b9a8f7b16546d28962edfc25e293.

</details>

<details>
<summary>📒 Files selected for processing (13)</summary>

* `.claude-plugin/marketplace.json`
* `PLUGINS.md`
* `docs/data.json`
* `plugins/jira/.claude-plugin/plugin.json`
* `plugins/jira/commands/candidates-from-pr.md`
* `plugins/jira/skills/candidates-from-pr/SKILL.md`
* `plugins/jira/skills/candidates-from-pr/scripts/build_jql.py`
* `plugins/jira/skills/candidates-from-pr/scripts/derive_filters.py`
* `plugins/jira/skills/candidates-from-pr/scripts/extract_jira_keys.py`
* `plugins/jira/skills/candidates-from-pr/scripts/extract_signals.py`
* `plugins/jira/skills/candidates-from-pr/scripts/fetch_pr.py`
* `plugins/jira/skills/candidates-from-pr/scripts/render_report.py`
* `plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py`

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* plugins/jira/.claude-plugin/plugin.json

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (8)</summary>

* .claude-plugin/marketplace.json
* plugins/jira/skills/candidates-from-pr/scripts/extract_signals.py
* docs/data.json
* plugins/jira/skills/candidates-from-pr/scripts/build_jql.py
* plugins/jira/skills/candidates-from-pr/scripts/render_report.py
* PLUGINS.md
* plugins/jira/skills/candidates-from-pr/scripts/derive_filters.py
* plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread plugins/jira/commands/candidates-from-pr.md
Comment thread plugins/jira/skills/candidates-from-pr/scripts/fetch_pr.py Outdated
Comment thread plugins/jira/skills/candidates-from-pr/SKILL.md Outdated
@qinqon qinqon marked this pull request as ready for review May 8, 2026 13:24
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 8, 2026
@openshift-ci openshift-ci Bot requested review from bryan-cox and enxebre May 8, 2026 13:24
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Tip

For best results, initiate chat on the files or code changes.

@qinqon: Thank you for the detailed breakdown! All the substantive fixes look great:

  • fetch_pr.py L77 — safe split-before-index guards against the IndexError on whitespace-only stderr.
  • SKILL.md prerequisites — jq added and Python bumped to 3.10+ (necessary for PEP 604 union syntax).
  • SKILL.md release-selection rule — "highest unreleased numeric version" now consistent with the command doc.
  • ✅ MD040 bare fences — tagged in both SKILL.md and candidates-from-pr.md.
  • ✅ Assignee schema — object form { display_name, email } now consistent across both docs.

The skipped score_candidates.py nits (lower() dead code, redundant elif, defensive .lower() in find_lower) are reasonable to defer — no behavioral impact as you note. Happy to open a follow-up issue to track them if that's useful.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch 2 times, most recently from c5665e0 to 34af796 Compare May 11, 2026 13:31
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
plugins/jira/skills/candidates-from-pr/scripts/build_jql.py (1)

34-39: 💤 Low value

Consider validating non-empty target_release.

If target_release is an empty string "", the current code will generate a version clause with empty quotes: ("Target Version" = "" OR fixVersion = ""). While this won't cause errors, it likely won't match any issues and may not be the intended behavior.

🔍 Optional defensive check
 target_release = filters.get("target_release")
-if target_release:
+if target_release and target_release.strip():
     parts.append(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/jira/skills/candidates-from-pr/scripts/build_jql.py` around lines 34
- 39, The code appends a JQL fragment when target_release exists but doesn't
guard against empty strings; update the logic in build_jql.py where
target_release is read from filters and used with quote(target_release) so you
only append to parts when target_release is a non-empty, non-whitespace string
(e.g. check if target_release and target_release.strip()), keeping the existing
clause format that uses "Target Version" and fixVersion and still using the
quote(...) helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@plugins/jira/skills/candidates-from-pr/scripts/build_jql.py`:
- Around line 34-39: The code appends a JQL fragment when target_release exists
but doesn't guard against empty strings; update the logic in build_jql.py where
target_release is read from filters and used with quote(target_release) so you
only append to parts when target_release is a non-empty, non-whitespace string
(e.g. check if target_release and target_release.strip()), keeping the existing
clause format that uses "Target Version" and fixVersion and still using the
quote(...) helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 99c0175d-4f00-4116-8d5a-554b27c9f53c

📥 Commits

Reviewing files that changed from the base of the PR and between c5665e0 and 34af796.

📒 Files selected for processing (13)
  • .claude-plugin/marketplace.json
  • PLUGINS.md
  • docs/data.json
  • plugins/jira/.claude-plugin/plugin.json
  • plugins/jira/commands/candidates-from-pr.md
  • plugins/jira/skills/candidates-from-pr/SKILL.md
  • plugins/jira/skills/candidates-from-pr/scripts/build_jql.py
  • plugins/jira/skills/candidates-from-pr/scripts/derive_filters.py
  • plugins/jira/skills/candidates-from-pr/scripts/extract_jira_keys.py
  • plugins/jira/skills/candidates-from-pr/scripts/extract_signals.py
  • plugins/jira/skills/candidates-from-pr/scripts/fetch_pr.py
  • plugins/jira/skills/candidates-from-pr/scripts/render_report.py
  • plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py
✅ Files skipped from review due to trivial changes (3)
  • plugins/jira/.claude-plugin/plugin.json
  • PLUGINS.md
  • plugins/jira/skills/candidates-from-pr/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • docs/data.json
  • .claude-plugin/marketplace.json
  • plugins/jira/skills/candidates-from-pr/scripts/derive_filters.py
  • plugins/jira/skills/candidates-from-pr/scripts/extract_signals.py
  • plugins/jira/skills/candidates-from-pr/scripts/score_candidates.py
  • plugins/jira/skills/candidates-from-pr/scripts/render_report.py

@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch from 34af796 to b67149e Compare May 12, 2026 02:32
@qinqon
Copy link
Copy Markdown
Author

qinqon commented May 12, 2026

Addressed remaining CodeRabbit nitpicks in c6080e0:

score_candidates.py:

  • Removed dead lower() helper (was never called).
  • Simplified redundant elif guard — the not (cand_components & derived_components) check is always true in the elif branch since it's the complement of the if above.
  • Added defensive .lower() in find_lower — upstream currently lowercases inputs, but this guards against future changes.

build_jql.py:

  • Added .strip() guard on target_release to avoid generating JQL with empty-string version clauses.

All scripts:

  • Added from __future__ import annotations to all 7 scripts for Python 3.9+ compatibility (PEP 604 union syntax str | None is used throughout).

@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch 3 times, most recently from b41c4c8 to 66444c8 Compare May 12, 2026 19:36
@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 15, 2026
@qinqon
Copy link
Copy Markdown
Author

qinqon commented May 19, 2026

CI Failure Analysis — commit 66444c8

Total failures: 1 (1 related)
Action taken: Pushed fix for related failure


🔴 Related: tide — fix pushed

Error

```
CONFLICT (content): Merge conflict in .claude-plugin/marketplace.json
CONFLICT (content): Merge conflict in docs/data.json
CONFLICT (content): Merge conflict in plugins/jira/.claude-plugin/plugin.json
Could not apply c874543... feat(jira): add candidates-from-pr command
```

Root Cause

The PR's 3 commits were based on an older main (commit 2550735) while origin/main had advanced 21 commits since then. The conflicts were in version number fields for the jira plugin across .claude-plugin/marketplace.json, docs/data.json, and plugins/jira/.claude-plugin/plugin.json -- upstream bumped jira from 0.4.4 to 0.4.5 while the PR had version 0.4.7/0.4.8.

Recommendation

The rebase has been completed successfully. All 3 commits are now rebased on top of origin/main with conflicts resolved (PR's version 0.4.7/0.4.8 kept over upstream's 0.4.5). Signed-off-by trailers updated to use full name. Push to update the PR.

Action

Pushed fix for this failure.

Pushed a fix for the related failure.

@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch from 66444c8 to 373f2c1 Compare May 19, 2026 06:15
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 19, 2026
@qinqon qinqon closed this May 20, 2026
@qinqon qinqon deleted the feat/jira-candidates-from-pr branch May 20, 2026 07:38
@qinqon qinqon restored the feat/jira-candidates-from-pr branch May 20, 2026 16:20
@qinqon qinqon reopened this May 20, 2026
@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 20, 2026
@qinqon
Copy link
Copy Markdown
Author

qinqon commented May 20, 2026

Rebased commit 373f2c1 on main and pushed (conflicts resolved).

@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch from 373f2c1 to 8a2666c Compare May 20, 2026 16:24
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 20, 2026
@qinqon
Copy link
Copy Markdown
Author

qinqon commented May 20, 2026

CI Failure Analysis — commit 373f2c1

Total failures: 1 (1 related)
Action taken: Pushed fix for related failure


🔴 Related: tide — fix pushed

Error

```
$ gh pr view 451 --repo openshift-eng/ai-helpers --json mergeable,mergeStateStatus
{"mergeStateStatus":"BLOCKED","mergeable":"MERGEABLE"}
$ git merge-base HEAD origin/main
d4833bac367a47cef3596398d30e53a06834d751  # matches origin/main HEAD
$ git rebase origin/main
Current branch feat/jira-candidates-from-pr is up to date.
```

Root Cause

The PR's branch had diverged from origin/main due to upstream commits. A prior rebase session resolved the version conflicts in marketplace.json, data.json, and plugin.json, and force-pushed to the fork. The tide check was reporting stale conflict status that has since cleared -- GitHub now reports the PR as MERGEABLE.

Recommendation

The merge conflict is already resolved. The PR is MERGEABLE on GitHub. Tide should pick it up on its next sync cycle. If tide still reports conflicts, retrigger with /retest.

Action

Pushed fix for this failure.

Pushed a fix for the related failure.

@qinqon
Copy link
Copy Markdown
Author

qinqon commented May 20, 2026

Rebased commit 8a2666c on main and pushed (conflicts resolved).

@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch from 8a2666c to 4aa2aaa Compare May 20, 2026 19:30
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 20, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: qinqon
Once this PR has been reviewed and has the lgtm label, please assign dgoodwin for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch from 4aa2aaa to 1949e3d Compare May 20, 2026 23:40
qinqon added 3 commits May 21, 2026 03:42
Adds /jira:candidates-from-pr, a read-only triage helper that takes a
GitHub PR and surfaces a ranked table of open Jira issues the PR may
fix, scoped by component and target release.

This is the inverse direction of /jira:extract-prs (Jira -> PRs). The
command extracts explicitly referenced Jira keys from the PR
title/body/commits separately, derives component and target release
from the PR's repo and base branch (with overrides), runs a JQL search
for open issues, and locally scores each candidate by symbol, error
string, keyword, and component overlap with the PR diff.

Output is a triage-ready table that includes assignee as a required
column (with an 'unassigned' fallback when the field is null), so the
report is actionable without additional Jira lookups. JSON output is
also supported for downstream tooling.

The command never mutates Jira state; it is intended to assist
maintainer triage when a PR was opened without a clear Jira link.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Enrique Llorente Pastora <ellorent@redhat.com>
- fetch_pr.py: guard against IndexError when gh stderr is whitespace-only
- SKILL.md: add jq + Python 3.10+ to prerequisites
- SKILL.md: 'highest' (not 'smallest') unreleased version for main/master,
  matching the command doc's wording
- SKILL.md, candidates-from-pr.md: tag bare fenced blocks (MD040)
- candidates-from-pr.md: align candidate `assignee` schema with SKILL.md
  (object with display_name/email, as returned by Jira)
- bump jira plugin to 0.4.8

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Enrique Llorente Pastora <ellorent@redhat.com>
- Remove dead lower() helper from score_candidates.py
- Simplify redundant elif guard in component check
- Add defensive .lower() in find_lower for case-insensitive matching
- Guard against empty target_release in build_jql.py
- Add from __future__ import annotations to all scripts for Python 3.9+

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Enrique Llorente Pastora <ellorent@redhat.com>
@qinqon qinqon force-pushed the feat/jira-candidates-from-pr branch from 1949e3d to e1b9981 Compare May 21, 2026 03:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant