Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions release_notes_generator/data/miner.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from github import Github
from github.GitRelease import GitRelease
from github.Issue import Issue
from github.PullRequest import PullRequest
from github.Repository import Repository

from release_notes_generator.action_inputs import ActionInputs
Expand Down Expand Up @@ -83,19 +84,25 @@ def mine_data(self) -> MinedData:

return de_duplicated_data

def mine_missing_sub_issues(self, data: MinedData) -> dict[Issue, Repository]:
def mine_missing_sub_issues(self, data: MinedData) -> tuple[dict[Issue, Repository], dict[str, list[PullRequest]]]:
"""
Mines missing sub-issues from GitHub.
Parameters:
data (MinedData): The mined data containing origin sets of issues and pull requests.
Returns:
dict[Issue, Repository]: A dictionary mapping fetched issues to their repositories.
dict[str, list[PullRequest]]: A dictionary mapping fetched cross-repo issue with its pull requests.
"""
logger.info("Mapping sub-issues...")
data.parents_sub_issues = self._scan_sub_issues_for_parents([get_id(i, r) for i, r in data.issues.items()])

logger.info("Fetching missing issues...")
return self._fetch_missing_issues_and_prs(data)
fetched_issues = self._fetch_missing_issues(data)

logger.info("Getting PRs and Commits for missing issues...")
prs_of_fetched_cross_repo_issues = self._fetch_prs_for_fetched_cross_issues(fetched_issues)

return fetched_issues, prs_of_fetched_cross_repo_issues

def _scan_sub_issues_for_parents(self, parents_to_check: list[str]) -> dict[str, list[str]]:
"""
Expand All @@ -119,7 +126,7 @@ def _scan_sub_issues_for_parents(self, parents_to_check: list[str]) -> dict[str,

return parents_sub_issues

def _fetch_missing_issues_and_prs(self, data: MinedData) -> dict[Issue, Repository]:
def _fetch_missing_issues(self, data: MinedData) -> dict[Issue, Repository]:
"""
Fetch missing issues.

Expand Down Expand Up @@ -167,6 +174,8 @@ def _fetch_missing_issues_and_prs(self, data: MinedData) -> dict[Issue, Reposito
else:
logger.debug("Skipping issue %s since it does not meet criteria.", parent_id)
issues_for_remove.append(parent_id)
else:
logger.error("Cannot get repository for issue %s. Skipping...", parent_id)

# remove issue which does not meet criteria
for iid in issues_for_remove:
Expand Down Expand Up @@ -350,3 +359,20 @@ def __filter_duplicated_issues(data: MinedData) -> "MinedData":

data.issues = filtered_issues
return data

def _fetch_prs_for_fetched_cross_issues(self, issues: dict[Issue, Repository]) -> dict[str, list[PullRequest]]:
prs_of_cross_repo_issues: dict[str, list[PullRequest]] = {}
for i, repo in issues.items():
prs_of_cross_repo_issues[iid := get_id(i, repo)] = []
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))

return prs_of_cross_repo_issues
4 changes: 3 additions & 1 deletion release_notes_generator/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ def generate(self) -> Optional[str]:

# data expansion when hierarchy is enabled
if ActionInputs.get_hierarchy():
data_filtered_by_release.issues.update(miner.mine_missing_sub_issues(data_filtered_by_release))
fetched_issues, prs_of_fetched_issues = miner.mine_missing_sub_issues(data_filtered_by_release)
data_filtered_by_release.issues.update(fetched_issues)
data_filtered_by_release.pull_requests_of_fetched_cross_issues = prs_of_fetched_issues
else:
# fill flat structure with empty lists, no hierarchy
for i, repo in data_filtered_by_release.issues.items():
Expand Down
2 changes: 2 additions & 0 deletions release_notes_generator/model/mined_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def __init__(self, repository: Repository):
self.commits: dict[Commit, Repository] = {}

self.parents_sub_issues: dict[str, list[str]] = {} # parent issue id -> list of its sub-issues ids
# dictionary of fetched cross issues and their pull requests
self.pull_requests_of_fetched_cross_issues: dict[str, list[PullRequest]] = {}

@property
def home_repository(self) -> Repository:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ def generate(self, data: MinedData) -> dict[str, Record]:
for pull, repo in data.pull_requests.items():
self._register_pull_and_its_commits_to_issue(pull, get_id(pull, repo), data, target_repository=repo)

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)

logger.debug("Registering direct commits to records...")
for commit, repo in data.commits.items():
if commit.sha not in self.__registered_commits:
Expand Down Expand Up @@ -180,6 +185,14 @@ def _register_pull_and_its_commits_to_issue(
self._records[pid] = pr_rec
logger.debug("Created record for PR %s: %s", pid, pull.title)

def _register_cross_repo_prs_to_issue(self, iid: str, prs: list[PullRequest]) -> None:
if iid not in self.__registered_issues:
logger.error("Issue '%s' not found among collected records.", iid)
return

for pr in prs:
cast(IssueRecord, self._records[iid]).register_pull_request(pr)

def _create_record_for_hierarchy_issue(self, i: Issue, iid: str, issue_labels: Optional[list[str]] = None) -> None:
"""
Create a hierarchy issue record and register sub-issues.
Expand Down
Loading