Skip to content

feat: use graph-based compare instead of timestamp when from-tag-name is set#317

Open
miroslavpojer wants to merge 5 commits into
masterfrom
feature/compare-mode-for-branching-releases
Open

feat: use graph-based compare instead of timestamp when from-tag-name is set#317
miroslavpojer wants to merge 5 commits into
masterfrom
feature/compare-mode-for-branching-releases

Conversation

@miroslavpojer
Copy link
Copy Markdown
Collaborator

@miroslavpojer miroslavpojer commented May 29, 2026

Problem

When generating release notes for a maintenance branch (v2.6.x) while a parallel development
branch (v2.7.x) is also active, the existing timestamp approach returns commits and PRs from both
branches. repo.get_commits(since=timestamp) has no concept of branch ancestry — it returns
everything in the time window regardless of which branch it lives on.

Example: generating notes for v2.6.5 (previous v2.6.4) picks up v2.7.0 and v2.7.1 PRs
that happened to be merged in the same window. The generated release notes are incorrect.

Cherry-picks compound the problem: the fetched PR object has merged_at equal to the original
develop merge date, so timestamp filtering can silently drop the cherry-picked fix from the
maintenance release notes entirely.

Solution

When from-tag-name is explicitly provided, use repo.compare(from_tag, to_tag) (GitHub Compare
API) instead of repo.get_commits(since=…). This is a graph-based operation — it returns only
commits reachable from to_tag but not from from_tag, independent of timestamps or branches.
PR numbers are then extracted from those commit messages and fetched individually by number.

FilterByRelease detects compare mode via a sentinel field (MinedData.compare_commit_shas) and
skips its timestamp check for PRs and commits — the set is already exact.

data.since is still derived from the previous release in compare mode; it is only used for issue
fetching and release-note extraction date-gating — not for PR/commit filtering.

Timestamp mode is unchanged when from-tag-name is absent.

Changes

File Change
release_notes_generator/model/mined_data.py Added compare_commit_shas: set[str] sentinel field
release_notes_generator/data/miner.py Compare-mode branch in mine_data(); _extract_pr_numbers_from_commits() static helper
release_notes_generator/data/filter.py Skip timestamp filter for PRs/commits when compare_commit_shas is non-empty
tests/unit/release_notes_generator/data/test_miner.py 17 new unit tests (7 for helper, 8 for compare path, 2 regression)
tests/unit/release_notes_generator/data/test_filter.py 5 new unit tests (3 compare mode, 2 timestamp regression)
tests/integration/test_compare_mode.py 4 new integration tests
docs/features/compare_mode.md New feature documentation page
docs/features/tag_range.md Linked compare mode in Related Features
README.md Added Compare Mode row in Feature Tutorials table
release_notes_generator/data/SPEC.md TDD spec with confirmed test table

Test coverage

  • 22 new unit tests (all green)
  • 4 new integration tests (all green)
  • 551 total tests passing

Release Notes

  • Compare mode — when from-tag-name is set, commits are selected via the GitHub Compare API instead of a timestamp window, giving correct results for branching release histories (maintenance + develop in parallel).
  • Timestamp mode unchanged — existing behaviour is preserved when from-tag-name is absent.

Related

Closes #316

Summary by CodeRabbit

  • New Features

    • Compare Mode: Improved commit and PR selection for repositories with complex branching histories, activated via tag-based release configuration.
  • Documentation

    • Added comprehensive Compare Mode feature documentation with configuration examples and data-flow diagrams.
    • Updated Tag Range Selection documentation with related feature reference.

- Introduced a new compare mode in the release notes generator to handle branching release histories.
- The compare mode activates when `from-tag-name` is provided, allowing for accurate commit selection based on the commit graph rather than timestamps.
- Added functionality to extract PR numbers from commit messages in both squash and merge formats.
- Updated `DataMiner` to utilize the GitHub Compare API for fetching commits unique to the current release.
- Enhanced filtering logic to retain PRs and commits in compare mode, regardless of their merge dates.
- Added comprehensive unit and integration tests to validate the new compare mode functionality.
- Documented the purpose, usage, and configuration of the compare mode in the relevant documentation files.
@miroslavpojer miroslavpojer self-assigned this May 29, 2026
@miroslavpojer miroslavpojer marked this pull request as draft May 29, 2026 13:59
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Review Change Stack

Walkthrough

This PR implements Compare Mode: when from-tag-name is explicitly set, release notes generation switches from timestamp-based to graph-based commit selection using GitHub's Compare API, solving multi-branch parallel release issues while extracting PR numbers from commit messages.

Changes

Compare Mode Feature

Layer / File(s) Summary
MinedData model with compare mode sentinel
release_notes_generator/model/mined_data.py
MinedData.__init__ now initializes compare_commit_shas: set[str] to track which commits were selected via graph comparison rather than timestamp filtering.
Compare mode mining and PR extraction
release_notes_generator/data/miner.py
DataMiner.mine_data() branches when from-tag-name is defined: calls repo.compare() instead of repo.get_commits(), extracts PR numbers from commit messages using regex (_extract_pr_numbers_from_commits), fetches each PR individually, and stores commit SHAs in the sentinel field; timestamp mode remains unchanged.
Miner behavior unit tests
tests/unit/release_notes_generator/data/test_miner.py
Tests validate PR extraction patterns (squash/merge/cherry-pick), compare-mode API usage (verify compare called, not get_commits), individual PR fetching, since selection logic, null-PR handling, commit SHAs recorded regardless, and timestamp-mode regression.
Compare mode filtering logic
release_notes_generator/data/filter.py
FilterByRelease.filter now branches on compare_commit_shas presence: compare mode passes all PRs/commits unfiltered; timestamp mode applies existing data.since-based filtering; issue filtering remains unchanged.
Filter behavior unit tests
tests/unit/release_notes_generator/data/test_filter.py
Tests verify compare-mode pass-through (PRs, commits, mixed) and timestamp-mode filtering (old PRs excluded, recent PRs retained).
Compare mode end-to-end integration tests
tests/integration/test_compare_mode.py
Integration tests confirm the full pipeline: compare mode includes PRs/commits dated before since in output, whereas timestamp mode excludes them; covers single, multiple PRs, and direct commits.
User-facing documentation and tutorials
docs/features/compare_mode.md, README.md, docs/features/tag_range.md
New Compare Mode tutorial explains activation semantics, graph-based selection, PR extraction behavior, and data.since scope; feature table and related-features links updated.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • AbsaOSS/generate-release-notes#148: Introduces/reshapes DataMiner and MinedData; this PR extends both with compare-mode-specific logic and fields.
  • AbsaOSS/generate-release-notes#192: Modifies FilterByRelease.filter around data.since filtering; this PR adds compare-mode bypass via compare_commit_shas, directly related at the same function.

Suggested labels

enhancement

Suggested reviewers

  • Zejnilovic
  • OlivieFranklova
  • benedeki

Poem

🐰 A rabbit hops through graphs so bright,
Where branches fork and tags unite,
No more timestamp guessing games—
Just commits and their rightful names!
Graph-based selection saves the day,
Compare Mode points the truest way! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: switching from timestamp-based to graph-based commit selection using the Compare API when from-tag-name is set.
Description check ✅ Passed The description comprehensively covers the problem, solution, all changed files, test coverage, and includes properly formatted release notes. It exceeds the template requirements.
Linked Issues check ✅ Passed All coding requirements from issue #316 are met: compare mode uses repo.compare() API, PR numbers are extracted from commits, FilterByRelease skips timestamp filtering via compare_commit_shas sentinel, and timestamp mode is preserved.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #316 objectives. Documentation updates, tests, and implementation changes all support the compare-mode feature without introducing unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/compare-mode-for-branching-releases

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

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a “compare mode” path to the release-notes mining pipeline so that when from-tag-name is provided, commits/PRs are selected via GitHub’s compare graph (ancestry-based) instead of a timestamp window—fixing incorrect results on parallel maintenance/develop branches and cherry-picks.

Changes:

  • Added compare_commit_shas to MinedData as a sentinel for compare mode.
  • Implemented compare-mode mining via repo.compare(from_tag, to_tag) and PR-number extraction from commit messages.
  • Updated filtering to bypass PR/commit timestamp reduction when compare mode is active; added unit + integration coverage and documentation.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
release_notes_generator/data/miner.py Adds compare-mode mining and PR-number extraction helper.
release_notes_generator/data/filter.py Skips PR/commit timestamp filtering when compare mode is detected.
release_notes_generator/model/mined_data.py Adds compare_commit_shas sentinel field.
tests/unit/release_notes_generator/data/test_miner.py Unit tests for PR extraction helper and compare-mode mining path.
tests/unit/release_notes_generator/data/test_filter.py Unit tests for compare-mode filter bypass + timestamp regressions.
tests/integration/test_compare_mode.py End-to-end integration coverage contrasting compare vs timestamp behavior.
docs/features/compare_mode.md New documentation page explaining compare mode behavior and rationale.
docs/features/tag_range.md Links tag-range feature docs to compare mode.
README.md Adds Compare Mode to the feature tutorial index.
release_notes_generator/data/SPEC.md Adds/updates spec describing compare-mode behavior and tests.

Comment thread release_notes_generator/data/miner.py
Comment thread release_notes_generator/data/miner.py
Copy link
Copy Markdown

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

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)

37-45: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Move imports to the top; don't interleave the module constant.

from github.Commit import Commit as GithubCommit (Line 37) is placed after the first-party imports, and _PR_NUMBER_RE (Line 39) is defined in the middle of the import block, with more imports following on Lines 40-45. This trips Pylint (wrong-import-position/wrong-import-order).

Group the github import with the other from github... imports (Lines 29-33) and define the constant after the logger declaration (Line 47).

♻️ Proposed reorganization
-from github.Commit import Commit as GithubCommit
-
-_PR_NUMBER_RE = re.compile(r"\(#(\d+)\)|Merge pull request #(\d+)")
 from release_notes_generator.model.record.issue_record import IssueRecord
 from release_notes_generator.model.mined_data import MinedData
 from release_notes_generator.model.record.pull_request_record import PullRequestRecord
 from release_notes_generator.utils.decorators import safe_call_decorator
 from release_notes_generator.utils.github_rate_limiter import GithubRateLimiter
 from release_notes_generator.utils.record_utils import get_id, parse_issue_id

Add the github import alongside the existing ones (near Line 33):

 from github.Repository import Repository
+from github.Commit import Commit as GithubCommit

And define the constant after the logger (Line 47):

 logger = logging.getLogger(__name__)
+
+_PR_NUMBER_RE = re.compile(r"\(#(\d+)\)|Merge pull request #(\d+)")

As per coding guidelines: "Keep imports at top of file".

🤖 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 `@release_notes_generator/data/miner.py` around lines 37 - 45, Move the github
import and the module-level constant so all imports remain grouped at the top:
relocate the line "from github.Commit import Commit as GithubCommit" to join the
other from github... imports (near the existing github import group) and remove
the inlined "_PR_NUMBER_RE" definition from the import block; then place the
"_PR_NUMBER_RE = re.compile(...)" constant immediately after the logger
declaration (the module-level logger variable) so imports are contiguous and the
constant is defined after logger as requested.
🧹 Nitpick comments (1)
tests/unit/release_notes_generator/data/test_miner.py (1)

528-569: ⚖️ Poor tradeoff

Private method exercised directly in tests.

These tests invoke DataMiner._extract_pr_numbers_from_commits(...) directly. Consider exercising this logic through a public entry point (e.g. via mine_data in compare mode, which the later tests already drive), or extracting the parser into a module-level helper so it can be tested without reaching into a private member.

As per coding guidelines: "Must not access private members (names starting with _) of the class under test directly in tests".

🤖 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 `@tests/unit/release_notes_generator/data/test_miner.py` around lines 528 -
569, Tests directly call the private method
DataMiner._extract_pr_numbers_from_commits; instead, either exercise this
behavior via the public DataMiner.mine_data (compare mode) or extract the
PR-number parsing into a new module-level helper function (e.g.,
parse_pr_numbers_from_commits) and update tests to call that public helper;
update references in tests from DataMiner._extract_pr_numbers_from_commits to
the chosen public entry (mine_data with appropriate inputs) or the new helper to
comply with the rule against accessing private members.
🤖 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 `@docs/features/compare_mode.md`:
- Around line 16-28: Update the fenced code blocks in
docs/features/compare_mode.md to include a language identifier (e.g., ```text)
so they no longer trigger MD040; specifically modify each triple-backtick block
showing the git graph snippets (the blocks starting with the
develop:/maintenance/v2.6.x lines and the other example block that starts with
"from-tag-name provided?") to use ```text instead of bare ```, ensuring all
occurrences noted in the comment (lines ~16–28 and ~103–118) are updated.

In `@release_notes_generator/data/filter.py`:
- Around line 96-109: This file fails Black formatting due to manually wrapped
logger.debug calls and comprehension wrapping around the pulls and commits
filtering; run Black (e.g., black release_notes_generator/data/filter.py or the
repo root) to auto-format the logger.debug invocations and the
commits_dict/pulls_dict comprehensions so they match the project's Black rules,
or manually reflow the logger.debug argument lines and the commits_dict
comprehension used with data.commits and data.since (and the earlier pulls_dict
usage with data.pull_requests) to conform to Black's preferred line breaks.

In `@release_notes_generator/data/miner.py`:
- Around line 74-75: Run Black on the repository (or this file) to fix
formatting; specifically reformat the multi-line logger.info call that passes
ActionInputs.get_from_tag_name() and ActionInputs.get_tag_name() so it matches
Black's expected layout (e.g. a single-line call or Black's preferred wrapped
form), and do the same for the other similar logger.info call later in the file
that wraps ActionInputs methods; search for logger.info and
ActionInputs.get_from_tag_name()/get_tag_name() to locate and reformat the
offending invocations.
- Around line 460-464: The PR-number extraction currently scans the entire
commit message via _PR_NUMBER_RE.finditer(message), which picks up references
from the body; limit the search to the commit subject only by extracting the
first line (e.g. subject = commit.commit.message.splitlines()[0] or
.partition('\n')[0]) and run _PR_NUMBER_RE.finditer(subject) so
pr_numbers.add(int(number_str)) only collects PRs referenced in the subject
(affects the loop handling commit, message, _PR_NUMBER_RE, and pr_numbers).
- Around line 76-81: The call to self._safe_call(repo.compare) can return None,
so before doing list(comparison.commits) guard against comparison being None
(similar to how get_release/get_repo are handled): check if comparison is falsy,
log or warn about the failed compare (include context like
ActionInputs.get_from_tag_name()/get_tag_name()), and return or populate data
with empty compare_commits/compare_commit_shas and data.commits as appropriate
to avoid the AttributeError; update the logic around comparison,
compare_commits, data.compare_commit_shas, and data.commits to handle the None
case.
- Around line 79-81: The code currently converts comparison.commits into
compare_commits and assumes it's complete; add a guard that compares
len(compare_commits) against comparison.total_commits (e.g., if
len(compare_commits) < comparison.total_commits:) and handle the PyGithub
pagination cap case by logging or raising a warning/error and avoiding silent
truncation before setting data.compare_commit_shas and data.commits (referencing
compare_commits, comparison.total_commits, data.compare_commit_shas, and
data.commits).

In `@release_notes_generator/data/SPEC.md`:
- Around line 14-26: The fenced code blocks in SPEC.md (the commit log block
starting with ``` and the git command block using ``` around git log --oneline
--right-only --cherry-pick v2.6.4...v2.6.5) are missing language identifiers and
trigger MD040; update those fences to include appropriate languages (e.g.,
change the commit-log fence to ```text and the git command fence to ```bash) so
the Markdown linter passes.

---

Outside diff comments:
In `@release_notes_generator/data/miner.py`:
- Around line 37-45: Move the github import and the module-level constant so all
imports remain grouped at the top: relocate the line "from github.Commit import
Commit as GithubCommit" to join the other from github... imports (near the
existing github import group) and remove the inlined "_PR_NUMBER_RE" definition
from the import block; then place the "_PR_NUMBER_RE = re.compile(...)" constant
immediately after the logger declaration (the module-level logger variable) so
imports are contiguous and the constant is defined after logger as requested.

---

Nitpick comments:
In `@tests/unit/release_notes_generator/data/test_miner.py`:
- Around line 528-569: Tests directly call the private method
DataMiner._extract_pr_numbers_from_commits; instead, either exercise this
behavior via the public DataMiner.mine_data (compare mode) or extract the
PR-number parsing into a new module-level helper function (e.g.,
parse_pr_numbers_from_commits) and update tests to call that public helper;
update references in tests from DataMiner._extract_pr_numbers_from_commits to
the chosen public entry (mine_data with appropriate inputs) or the new helper to
comply with the rule against accessing private members.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9419181-1673-4e3c-a740-cbcd97701a09

📥 Commits

Reviewing files that changed from the base of the PR and between d5707d6 and 82e6b5c.

📒 Files selected for processing (10)
  • README.md
  • docs/features/compare_mode.md
  • docs/features/tag_range.md
  • release_notes_generator/data/SPEC.md
  • release_notes_generator/data/filter.py
  • release_notes_generator/data/miner.py
  • release_notes_generator/model/mined_data.py
  • tests/integration/test_compare_mode.py
  • tests/unit/release_notes_generator/data/test_filter.py
  • tests/unit/release_notes_generator/data/test_miner.py

Comment thread docs/features/compare_mode.md Outdated
Comment thread release_notes_generator/data/filter.py
Comment thread release_notes_generator/data/miner.py Outdated
Comment thread release_notes_generator/data/miner.py Outdated
Comment thread release_notes_generator/data/miner.py
Comment thread release_notes_generator/data/miner.py
Comment thread release_notes_generator/data/SPEC.md Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread release_notes_generator/data/SPEC.md Outdated
Comment thread release_notes_generator/data/miner.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

@miroslavpojer miroslavpojer marked this pull request as ready for review June 1, 2026 11:29
Copy link
Copy Markdown

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

🧹 Nitpick comments (1)
tests/unit/release_notes_generator/data/test_miner.py (1)

723-744: ⚡ Quick win

Consider covering the comparison is None guard.

The repo.compareNone path (miner.py Lines 82-88) that logs an error and calls sys.exit(1) is not exercised by any unit test. A small test patching mock_repo.compare.return_value = None and asserting sys.exit would lock in that error-exit behavior.

🤖 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 `@tests/unit/release_notes_generator/data/test_miner.py` around lines 723 -
744, Add a unit test that exercises the repo.compare → None branch: in the test
(similar to test_mine_data_compare_mode_warns_on_retrieval_cap_without_total)
patch mock_repo.compare.return_value = None, patch sys.exit (or mock it) and
patch the error logger used in release_notes_generator.data.miner, then call
miner.mine_data() and assert that the error log was emitted and sys.exit was
invoked; reference the miner.mine_data method and the repo.compare behavior so
the test covers the comparison is None guard.
🤖 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 `@tests/unit/release_notes_generator/data/test_miner.py`:
- Around line 702-744: Add a one-line docstring to each new test function to
state its scenario: for
test_mine_data_compare_mode_warns_on_total_commits_overflow add a docstring like
"Warns when compare mode reports a larger total_commits than retrieved commits
(overflow case)"; for
test_mine_data_compare_mode_warns_on_retrieval_cap_without_total add a docstring
like "Warns when retrieval reaches the internal cap (10,000) but no
total_commits value is provided"; place each docstring as the first statement
inside the respective functions
(test_mine_data_compare_mode_warns_on_total_commits_overflow and
test_mine_data_compare_mode_warns_on_retrieval_cap_without_total).

---

Nitpick comments:
In `@tests/unit/release_notes_generator/data/test_miner.py`:
- Around line 723-744: Add a unit test that exercises the repo.compare → None
branch: in the test (similar to
test_mine_data_compare_mode_warns_on_retrieval_cap_without_total) patch
mock_repo.compare.return_value = None, patch sys.exit (or mock it) and patch the
error logger used in release_notes_generator.data.miner, then call
miner.mine_data() and assert that the error log was emitted and sys.exit was
invoked; reference the miner.mine_data method and the repo.compare behavior so
the test covers the comparison is None guard.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7600d2f0-a0a7-43e0-9c0f-36bd6fca4832

📥 Commits

Reviewing files that changed from the base of the PR and between 82e6b5c and cf95f48.

📒 Files selected for processing (4)
  • docs/features/compare_mode.md
  • release_notes_generator/data/filter.py
  • release_notes_generator/data/miner.py
  • tests/unit/release_notes_generator/data/test_miner.py
✅ Files skipped from review due to trivial changes (1)
  • docs/features/compare_mode.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • release_notes_generator/data/filter.py

Comment on lines +702 to +744
def test_mine_data_compare_mode_warns_on_total_commits_overflow(mocker, mock_repo):
commit_mock = mocker.Mock()
commit_mock.sha = "abc123"
commit_mock.commit.message = "Fix service access role (#1363)"
warning_mock = mocker.patch("release_notes_generator.data.miner.logger.warning")

miner = _make_compare_miner(
mocker,
mock_repo,
compare_commits=[commit_mock],
total_commits=10_001,
)
miner.mine_data()

warning_mock.assert_called_once_with(
"Compare mode: retrieved %d commit(s) but comparison reports %d total; results may be truncated.",
1,
10_001,
)


def test_mine_data_compare_mode_warns_on_retrieval_cap_without_total(mocker, mock_repo):
commits = []
for i in range(10_000):
commit_mock = mocker.Mock()
commit_mock.sha = f"sha{i}"
commit_mock.commit.message = "Commit without PR ref"
commits.append(commit_mock)

warning_mock = mocker.patch("release_notes_generator.data.miner.logger.warning")

miner = _make_compare_miner(
mocker,
mock_repo,
compare_commits=commits,
)
miner.mine_data()

warning_mock.assert_called_once_with(
"Compare mode: retrieved %d commit(s); comparison ranges over %d commits may be truncated.",
10_000,
10_000,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add scenario docstrings to the new tests.

test_mine_data_compare_mode_warns_on_total_commits_overflow and test_mine_data_compare_mode_warns_on_retrieval_cap_without_total have no docstring describing their scenario.

As per coding guidelines: "each test must state its scenario in the docstring".

🤖 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 `@tests/unit/release_notes_generator/data/test_miner.py` around lines 702 -
744, Add a one-line docstring to each new test function to state its scenario:
for test_mine_data_compare_mode_warns_on_total_commits_overflow add a docstring
like "Warns when compare mode reports a larger total_commits than retrieved
commits (overflow case)"; for
test_mine_data_compare_mode_warns_on_retrieval_cap_without_total add a docstring
like "Warns when retrieval reaches the internal cap (10,000) but no
total_commits value is provided"; place each docstring as the first statement
inside the respective functions
(test_mine_data_compare_mode_warns_on_total_commits_overflow and
test_mine_data_compare_mode_warns_on_retrieval_cap_without_total).

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.

fix: use graph-based compare instead of timestamp when from-tag-name is set

2 participants