Skip to content

chore: add script to generate release notes based on commit history#12900

Open
meltsufin wants to merge 17 commits intomainfrom
impl/release-note-generator
Open

chore: add script to generate release notes based on commit history#12900
meltsufin wants to merge 17 commits intomainfrom
impl/release-note-generator

Conversation

@meltsufin
Copy link
Copy Markdown
Member

@meltsufin meltsufin commented Apr 23, 2026

The script takes the following inputs:

  • module name: as specified in versions.txt
  • module directory: path in the monorepo
  • version: version as found in versions.txt

It scans backwards through the git history of versions.txt to find the commit where the version was changed to the provided version. It then finds the commit where the previous non-snapshot version was set. It uses this commit range to generate the commit history affecting that directory.

This also adds missing release notes for spanner and bigquery.

Fixes #12864.

The script takes the following inputs:
- module name: as specified in versions.txt
- module directory: path in the monorepo
- version: version as found in versions.txt

It scans backwards through the git history of versions.txt to find the commit where the version was changed to the provided version. It then finds the commit where the previous non-snapshot version was set. It uses this commit range to generate the commit history affecting that directory.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a script to automate the generation of release notes based on commit history for specific modules. The review identified several improvements: the module name should be escaped in regex patterns to prevent issues with special characters, progress messages should be directed to stderr to avoid polluting output, and the logic for handling initial releases needs adjustment to ensure the full commit history is included.

Comment thread .github/release-note-generation/generate_module_notes.py Outdated
Comment thread .github/release-note-generation/generate_module_notes.py Outdated
Comment thread .github/release-note-generation/generate_module_notes.py Outdated
Comment thread .github/release-note-generation/generate_module_notes.py Outdated
Comment thread .github/release-note-generation/generate_module_notes.py
Comment thread .github/release-note-generation/generate_module_notes.py Outdated
…e note generator

Addresses feedback from gemini-code-assist:
- Escaped module name in regex patterns.
- Redirected informational logs to stderr.
- Adjusted initial release range logic to include the full history.
Adds unit tests that compare the script output against saved golden files:
- Root generation for monorepo version 1.85.0.
- Module generation for java-run at version 0.71.0.
Removes the --first-parent restriction from all Git commands in the script:
- versions.txt history scanning.
- Fallback for initial releases.
- Commit extraction for release notes.
This allows capturing commits from side branches that were not squashed, while relying on prefix filters to remove noise.
Implements a fallback to scan pom.xml history when versions.txt lacks records:
- Finds the commit that changed the version away from the target version.
- Finds the commit that set the previous stable version.
- Calculates the exclusive range between these events to avoid boundary overlaps.
@meltsufin
Copy link
Copy Markdown
Member Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a Python script, generate_module_notes.py, designed to automate the generation of release notes for specific modules within a monorepo by analyzing Git history and commit messages. It includes a fallback mechanism to scan pom.xml files when versions.txt history is insufficient. Feedback identifies a potential issue with the regex used for version extraction in Maven files, which might incorrectly capture parent POM versions. Additionally, a logic bug was noted in the commit range calculation when using pom.xml history, specifically regarding how the target commit is identified and handled when it is the most recent change.

except SystemExit:
continue

match = re.search(r"<version>([^<]+)</version>", content)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The regex used to extract the version from pom.xml is too broad. re.search(r"<version>([^<]+)</version>", content) will match the first occurrence of a <version> tag, which in many Maven files belongs to the <parent> block rather than the project itself. This could lead to incorrect version detection if the module has a parent POM with a different version. Consider using a more specific regex that targets the project's version, for example by looking for the version tag that follows the project's <artifactId>.

Comment on lines +118 to +160
target_end_commit = None
prev_start_commit = None

for commit in pom_commits:
show_cmd = ["git", "show", f"{commit}:{pom_path}"]
try:
content = run_cmd(show_cmd)
except SystemExit:
continue

match = re.search(r"<version>([^<]+)</version>", content)
if match:
ver = match.group(1)

if ver == target_version and not target_end_commit:
# Moving backwards, this is the first commit with target version!
# The previous commit in loop was the one that changed it AWAY from target version!
target_end_commit = prev_commit_in_loop
print(
f"Found commit changing away from {target_version} at {target_end_commit}",
file=sys.stderr,
)

elif (
target_end_commit
and ver != target_version
and "-SNAPSHOT" not in ver
):
# This is the commit where the previous stable version was set!
prev_start_commit = commit
print(
f"Found previous stable version {ver} at {commit}",
file=sys.stderr,
)
break

prev_commit_in_loop = commit

if prev_start_commit and target_end_commit:
prev_commit = prev_start_commit
# Use W~1 to be exclusive of W (the commit that changed it away)
target_commit = f"{target_end_commit}~1"
print(f"Using range derived from pom.xml: {prev_commit}..{target_commit}", file=sys.stderr)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The logic for determining the commit range from pom.xml history has a bug when multiple commits have the same target_version or when the target_version is the current tip of the branch.

  1. Falsy check: if ver == target_version and not target_end_commit: treats None as falsy. If the target version is found in the first commit of the log (pom_commits[0]), target_end_commit is set to None. In the next iteration, not target_end_commit will be true again, and it will incorrectly overwrite target_end_commit with the previous commit hash.
  2. Off-by-one/Missing commits: If target_end_commit is incorrectly set to a commit hash instead of None, the range target_end_commit~1 might exclude the most recent commits.
  3. Invalid reference: If target_end_commit remains None (e.g., if the version was only found in the first commit), line 159 will attempt to create an invalid git reference None~1.

Consider using a sentinel value or a boolean flag to correctly track when the target version range end is found.

            target_end_commit = "NOT_FOUND"
            prev_start_commit = None
            found_target = False

            for commit in pom_commits:
                show_cmd = ["git", "show", f"{commit}:{pom_path}"]
                try:
                    content = run_cmd(show_cmd)
                except SystemExit:
                    continue

                match = re.search(r"<version>([^<]+)</version>", content)
                if match:
                    ver = match.group(1)

                    if ver == target_version:
                        found_target = True
                        if target_end_commit == "NOT_FOUND":
                            # Moving backwards, this is the first commit with target version!
                            # The previous commit in loop was the one that changed it AWAY from target version!
                            target_end_commit = prev_commit_in_loop

                    elif (
                        found_target
                        and ver != target_version
                        and "-SNAPSHOT" not in ver
                    ):
                        # This is the commit where the previous stable version was set!
                        prev_start_commit = commit
                        print(
                            f"Found previous stable version {ver} at {commit}",
                            file=sys.stderr,
                        )
                        break

                prev_commit_in_loop = commit

            if prev_start_commit and found_target:
                prev_commit = prev_start_commit
                if target_end_commit != "NOT_FOUND" and target_end_commit is not None:
                    # Use W~1 to be exclusive of W (the commit that changed it away)
                    target_commit = f"{target_end_commit}~1"
                else:
                    # Target version is the current version, use the latest commit in the log
                    target_commit = pom_commits[0]
                print(f"Using range derived from pom.xml: {prev_commit}..{target_commit}", file=sys.stderr)

Updates the generator script to:
- Use commit hashes in compare links.
- Add commit links to items.
- Retain conventional commit prefixes.
- Omit PR links as requested.
Also updates the golden files to match the new formatting.
Backfills release notes for Spanner versions that were released on Maven Central but missing from the monorepo changelog:
- v6.113.0
- v6.114.0
- v6.115.0
- v6.116.0
- v6.116.1
Generated using the custom release note generator script with pom.xml fallback.
Backfills release notes for Spanner versions v6.113.0 to v6.116.1 using the refined lifecycle rule:
- Excludes commits with the target version in file state.
- Includes commits with previous release version or target snapshot.
This accurately reflects when work was done leading up to each release.
- Adds file existence check before running git show to eliminate noisy errors in helper function.
- Updates golden files to match the output with the final rules and forward scan logic.
…hangelog

- Implements inclusive lower boundary and other refinements in script.
- Updates golden files to match the final output.
- Updates Spanner changelog with the final backfilled notes.

### Bug Fixes

* fix(bqjdbc): lazily instantiate Statement in BigQueryDatabaseMetaData (#12752) ([72e5508](https://github.com/googleapis/google-cloud-java/commit/72e5508669ea48cde28f02adfeedfb05cd73fc57))
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@logachev Does this look right for Bigquery for filling the missed versions?

Comment thread java-spanner/CHANGELOG.md
@@ -1,5 +1,37 @@
# Changelog

## [6.116.1](https://github.com/googleapis/google-cloud-java/compare/966e8a4d99b...cd6048171fc) (2026-04-21)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@olavloite Does this look like the right release notes for these recent releases?

@meltsufin meltsufin requested a review from blakeli0 April 25, 2026 01:44
@meltsufin meltsufin marked this pull request as ready for review April 25, 2026 01:44
@meltsufin meltsufin requested review from a team as code owners April 25, 2026 01:44
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.

Changelog was not updated in the last release

1 participant