Skip to content

Conversation

miroslavpojer
Copy link
Collaborator

@miroslavpojer miroslavpojer commented Oct 4, 2025

Release Notes:

  • Added mining of Pull Requests for cross-repo issues.

Summary by CodeRabbit

  • New Features
    • Release notes now include pull requests discovered via cross-referenced issues across repositories, giving more complete coverage of related work.
    • Cross-repo pull requests are automatically associated with their corresponding issues in generated records and outputs.
    • Aggregation of fetched sub-issues and their related pull requests improved for more accurate linkage and display in outputs.

Fixes #174

- Added mining of Pull Requests for cross-repo issues.
@miroslavpojer miroslavpojer self-assigned this Oct 4, 2025
Copy link

coderabbitai bot commented Oct 4, 2025

Walkthrough

The miner now returns a pair: fetched cross-repo issues and their PR mappings. MinedData gains a dict to store PRs of fetched cross-issues. Generator updates to consume the new return type and persist the PR mapping. DefaultRecordFactory registers those cross-repo PRs to corresponding issue records, introducing a new helper method (duplicated in the class).

Changes

Cohort / File(s) Summary
Data mining outputs
release_notes_generator/data/miner.py
mine_missing_sub_issues return type changed to tuple of (dict[Issue, Repository], dict[str, list[PullRequest]]). Added _fetch_prs_for_fetched_cross_issues to build PR lists from cross-referenced timeline events; renamed _fetch_missing_issues_and_prs_fetch_missing_issues. Added logging for missing repos and imported PullRequest.
Data propagation
release_notes_generator/generator.py
Adjusted to unpack (fetched_issues, prs_of_fetched_issues) from miner; updates data_filtered_by_release.issues and sets data_filtered_by_release.pull_requests_of_fetched_cross_issues.
Data model extension
release_notes_generator/model/mined_data.py
Added pull_requests_of_fetched_cross_issues: dict[str, list[PullRequest]] initialized in __init__.
Record registration
release_notes_generator/record/factory/default_record_factory.py
After normal PR-to-issue registration, iterates data.pull_requests_of_fetched_cross_issues and registers PRs to issues. Introduced _register_cross_repo_prs_to_issue(iid, prs) (note: helper appears duplicated in class).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Generator
  participant DataMiner
  participant MinedData
  participant RecordFactory

  User->>Generator: generate(release, hierarchy=True)
  Generator->>DataMiner: mine_missing_sub_issues(data)
  DataMiner-->>Generator: (fetchedIssues, crossIssuePRs)
  Generator->>MinedData: issues.update(fetchedIssues)
  Generator->>MinedData: set pull_requests_of_fetched_cross_issues = crossIssuePRs
  Generator->>RecordFactory: build records from MinedData
  RecordFactory->>RecordFactory: register PRs for in-repo issues
  RecordFactory->>RecordFactory: register PRs for cross-repo issues (new)
  RecordFactory-->>User: records
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • Zejnilovic
  • benedeki

Poem

I hop through repos, ear to the wire,
Fetching cross-issue PRs to stoke the release fire.
Tuple in paw, I map and I bind,
Records aligned, no PR left behind.
Thump-thump—notes compiled, neat and tight. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description does not follow the repository’s required template because it lacks the checklist section and additional context headings and instead uses a non-standard "Release Notes" header instead of the designated PR summary format. Please update the description to include a clear PR summary, fill out the “## Checklist” section according to the template, add any relevant context under “## Additional Context,” and ensure the template’s structure is followed.
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title succinctly summarizes the main feature of fetching pull requests for cross-repo sub-issues and directly reflects the linked issue’s requirement without including extraneous details.
Linked Issues Check ✅ Passed The implementation adds a helper to fetch pull requests for cross-repository issues, adjusts the mining and data models to return and store these PRs, and updates record registration to include cross-repo PRs, fulfilling the feature objective of issue #174.
Out of Scope Changes Check ✅ Passed All modifications directly relate to adding and handling pull requests for cross-repo sub-issues as specified in the linked issue, and there are no unrelated or extra changes present.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/174-Add-logic-for-fetching-cross-repo-sub-issues's-PRs

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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
release_notes_generator/data/miner.py (1)

1-1: Fix Black formatting to unblock CI/CD.

The Black formatting check failed, preventing the pipeline from passing. Run the formatter to resolve this blocking issue.

#!/bin/bash
# Format the code with Black
black release_notes_generator/data/miner.py
🧹 Nitpick comments (2)
release_notes_generator/data/miner.py (1)

87-104: LGTM with suggestions.

The method signature change to return a tuple is correctly implemented and properly integrates the cross-repo PR fetching functionality.

Consider renaming _fetch_missing_issues_and_prs (line 99) to _fetch_missing_issues since it no longer returns PRs. The current name could be misleading to future maintainers.

-        fetched_issues = self._fetch_missing_issues_and_prs(data)
+        fetched_issues = self._fetch_missing_issues(data)

And update the method name at its definition (line 128):

-    def _fetch_missing_issues_and_prs(self, data: MinedData) -> dict[Issue, Repository]:
+    def _fetch_missing_issues(self, data: MinedData) -> dict[Issue, Repository]:
release_notes_generator/record/factory/default_record_factory.py (1)

100-103: Simplify the condition check.

Using .items() in a boolean context is unnecessarily verbose. An empty dict is falsy in Python.

Apply this diff to simplify the condition:

-        if data.pull_requests_of_fetched_cross_issues.items():
+        if data.pull_requests_of_fetched_cross_issues:
             logger.debug("Register cross-repo Pull Requests to its issues")
             for iid, prs in data.pull_requests_of_fetched_cross_issues.items():
                 self._register_cross_repo_prs_to_issue(iid, prs)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41deabb and 09f876f.

📒 Files selected for processing (4)
  • release_notes_generator/data/miner.py (5 hunks)
  • release_notes_generator/generator.py (2 hunks)
  • release_notes_generator/model/mined_data.py (1 hunks)
  • release_notes_generator/record/factory/default_record_factory.py (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-28T14:13:38.979Z
Learnt from: miroslavpojer
PR: AbsaOSS/generate-release-notes#173
File: release_notes_generator/record/factory/default_record_factory.py:109-126
Timestamp: 2025-09-28T14:13:38.979Z
Learning: In release_notes_generator/record/factory/default_record_factory.py, there is a cross-repo fetch bug where parent_issue_id in format "owner/repo#number" is fetched from the wrong repository because the code only queries data.repository instead of parsing the owner/repo from the ID and using the GitHub client to fetch from the correct repository.

Applied to files:

  • release_notes_generator/record/factory/default_record_factory.py
🧬 Code graph analysis (3)
release_notes_generator/data/miner.py (2)
release_notes_generator/model/mined_data.py (1)
  • MinedData (38-81)
release_notes_generator/utils/record_utils.py (1)
  • get_id (24-45)
release_notes_generator/generator.py (1)
release_notes_generator/data/miner.py (1)
  • mine_missing_sub_issues (87-104)
release_notes_generator/record/factory/default_record_factory.py (1)
release_notes_generator/model/issue_record.py (1)
  • register_pull_request (199-206)
🪛 GitHub Actions: Build and Test
release_notes_generator/data/miner.py

[error] 1-1: Black formatting check failed. Command 'black --check $(git ls-files "*.py")' exited with code 1. 1 file would be reformatted.

🪛 Ruff (0.13.3)
release_notes_generator/data/miner.py

362-362: Unused method argument: data

(ARG002)

🔇 Additional comments (3)
release_notes_generator/generator.py (1)

96-98: LGTM!

The tuple unpacking and assignment logic correctly integrates the new cross-repo PR fetching functionality. The code properly updates the filtered data with both fetched issues and their associated PRs.

release_notes_generator/model/mined_data.py (1)

53-54: LGTM!

The new attribute pull_requests_of_fetched_cross_issues is properly typed, documented, and initialized. It follows the existing patterns in the MinedData class and correctly supports the cross-repo PR mapping feature.

release_notes_generator/data/miner.py (1)

176-177: LGTM!

The else clause provides appropriate error logging when the repository cannot be fetched for a cross-repo issue.

Comment on lines 188 to 190
def _register_cross_repo_prs_to_issue(self, iid: str, prs: list[PullRequest]) -> None:
for pr in prs:
cast(IssueRecord, self._records[iid]).register_pull_request(pr)
Copy link

@coderabbitai coderabbitai bot Oct 4, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add validation before casting and accessing records.

The method lacks validation that could prevent runtime errors:

  1. No check that iid exists in self._records (could raise KeyError)
  2. No check that the record is an IssueRecord before casting (could raise AttributeError if the wrong record type)

Apply this diff to add defensive checks:

 def _register_cross_repo_prs_to_issue(self, iid: str, prs: list[PullRequest]) -> None:
+    if iid not in self._records:
+        logger.warning("Issue %s not found in records. Skipping cross-repo PR registration.", iid)
+        return
+    if not isinstance(self._records[iid], IssueRecord):
+        logger.warning("Record %s is not an IssueRecord. Skipping cross-repo PR registration.", iid)
+        return
     for pr in prs:
         cast(IssueRecord, self._records[iid]).register_pull_request(pr)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _register_cross_repo_prs_to_issue(self, iid: str, prs: list[PullRequest]) -> None:
for pr in prs:
cast(IssueRecord, self._records[iid]).register_pull_request(pr)
def _register_cross_repo_prs_to_issue(self, iid: str, prs: list[PullRequest]) -> None:
- for pr in prs:
if iid not in self._records:
logger.warning(
"Issue %s not found in records. Skipping cross-repo PR registration.",
iid,
)
return
if not isinstance(self._records[iid], IssueRecord):
logger.warning(
"Record %s is not an IssueRecord. Skipping cross-repo PR registration.",
iid,
)
return
for pr in prs:
cast(IssueRecord, self._records[iid]).register_pull_request(pr)
🤖 Prompt for AI Agents
In release_notes_generator/record/factory/default_record_factory.py around lines
188 to 190, the helper assumes self._records[iid] exists and is an IssueRecord;
add defensive checks before casting and calling register_pull_request: first
verify iid in self._records (if missing either log a warning and return or raise
a KeyError with a clear message), then fetch the record and validate
isinstance(record, IssueRecord) (if not, log or raise a TypeError indicating the
unexpected record type), and only then iterate prs and call
record.register_pull_request(pr); keep behavior consistent with surrounding
error-handling/logging conventions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Improved.

Copy link

Choose a reason for hiding this comment

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

@miroslavpojer, great! Thank you for adding the defensive checks to ensure the method handles edge cases safely. This will prevent potential runtime errors when dealing with cross-repo PRs.


🧠 Learnings used
Learnt from: miroslavpojer
PR: AbsaOSS/generate-release-notes#173
File: release_notes_generator/record/factory/default_record_factory.py:109-126
Timestamp: 2025-09-28T14:13:38.979Z
Learning: In release_notes_generator/record/factory/default_record_factory.py, there is a cross-repo fetch bug where parent_issue_id in format "owner/repo#number" is fetched from the wrong repository because the code only queries data.repository instead of parsing the owner/repo from the ID and using the GitHub client to fetch from the correct repository.

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

Thank you for using CodeRabbit!

Copy link

@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: 0

🧹 Nitpick comments (1)
release_notes_generator/data/miner.py (1)

367-376: Narrow the exception handling scope.

Line [375] currently catches bare Exception, which masks programming errors and Ruff flags it (BLE001). Please guard the attribute access up front and only swallow the expected API/attribute failures so unexpected bugs still surface.

Apply this diff:

             try:
-                for ev in i.get_timeline():  # timeline includes cross-references
-                    if ev.event == "cross-referenced" and getattr(ev, "source", None):
-                        # <- this is a github.Issue.Issue
-                        src_issue = ev.source.issue  # type: ignore[union-attr]
-                        if getattr(src_issue, "pull_request", None):
-                            pr = src_issue.as_pull_request()  # github.PullRequest.PullRequest
-                            prs_of_cross_repo_issues[iid].append(pr)
-            except Exception as e:
-                logger.warning("Failed to fetch timeline events for issue %s: %s", iid, str(e))
+                for ev in i.get_timeline():  # timeline includes cross-references
+                    if ev.event != "cross-referenced":
+                        continue
+                    source_issue = getattr(getattr(ev, "source", None), "issue", None)
+                    if source_issue is None:
+                        continue
+                    if getattr(source_issue, "pull_request", None):
+                        pr = source_issue.as_pull_request()  # github.PullRequest.PullRequest
+                        prs_of_cross_repo_issues[iid].append(pr)
+            except (GithubException, AttributeError, TypeError) as exc:
+                logger.warning("Failed to fetch timeline events for issue %s: %s", iid, exc)

Add alongside the other imports:

from github.GithubException import GithubException

Based on static analysis hints.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09f876f and 87a1d0c.

📒 Files selected for processing (3)
  • release_notes_generator/data/miner.py (5 hunks)
  • release_notes_generator/generator.py (1 hunks)
  • release_notes_generator/record/factory/default_record_factory.py (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-28T14:13:38.979Z
Learnt from: miroslavpojer
PR: AbsaOSS/generate-release-notes#173
File: release_notes_generator/record/factory/default_record_factory.py:109-126
Timestamp: 2025-09-28T14:13:38.979Z
Learning: In release_notes_generator/record/factory/default_record_factory.py, there is a cross-repo fetch bug where parent_issue_id in format "owner/repo#number" is fetched from the wrong repository because the code only queries data.repository instead of parsing the owner/repo from the ID and using the GitHub client to fetch from the correct repository.

Applied to files:

  • release_notes_generator/record/factory/default_record_factory.py
🧬 Code graph analysis (3)
release_notes_generator/generator.py (1)
release_notes_generator/data/miner.py (1)
  • mine_missing_sub_issues (87-105)
release_notes_generator/record/factory/default_record_factory.py (1)
release_notes_generator/model/issue_record.py (1)
  • register_pull_request (199-206)
release_notes_generator/data/miner.py (2)
release_notes_generator/model/mined_data.py (1)
  • MinedData (38-81)
release_notes_generator/utils/record_utils.py (1)
  • get_id (24-45)
🪛 Ruff (0.13.3)
release_notes_generator/data/miner.py

375-375: Do not catch blind exception: Exception

(BLE001)

@miroslavpojer miroslavpojer merged commit 2fd72de into master Oct 4, 2025
7 checks passed
@miroslavpojer miroslavpojer deleted the feature/174-Add-logic-for-fetching-cross-repo-sub-issues's-PRs branch October 4, 2025 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add logic for fetching cross-repo sub issues's PRs

1 participant