From 990b7f17f34fef02f103c1196efea6d0a15002ee Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 15 Sep 2026 09:44:27 +0800 Subject: [PATCH 1/2] Add comments in version catalog reminding to update changelogs on version bumps --- gradle/libs.versions.toml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 194523eb4b..aac6c26be0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,9 +2,12 @@ jdk-release = "17" durian = "1.2.0" selfie = "3.1.1" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. jackson = "2.20.1" maven-api = "3.0" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. ktlint = "1.8.0" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. javaparser = "3.27.1" [libraries] @@ -31,6 +34,7 @@ ktlint-ruleset-standard = { module = "com.pinterest.ktlint:ktlint-ruleset-standa javaparser-core = { module = "com.github.javaparser:javaparser-core", version.ref = "javaparser" } javaparser-symbol-solver-core = { module = "com.github.javaparser:javaparser-symbol-solver-core", version.ref = "javaparser" } +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. palantir-java-format-default = "com.palantir.javaformat:palantir-java-format:2.80.0" jgit = "org.eclipse.jgit:org.eclipse.jgit:7.7.1.202607240634-r" @@ -49,24 +53,41 @@ plexus-build-api = "org.sonatype.plexus:plexus-build-api:0.0.7" concurrent-trees = "com.googlecode.concurrent-trees:concurrent-trees:2.6.1" owasp-encoder = "org.owasp.encoder:encoder:1.4.0" mustache-compiler = "com.github.spullara.mustache.java:compiler:0.9.14" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. adocfmt = "org.drjekyll:adocfmt:0.3.1" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. antlr4-formatter = "com.khubla.antlr4formatter:antlr4-formatter:1.2.1" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. cleanthat-java = "io.github.solven-eu.cleanthat:java:2.25" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. cool-rdf-formatter = "cool.rdf:cool-rdf-formatter:2.0.1" diktat-rules = "org.cqfn.diktat:diktat-rules:1.2.5" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. diktat-runner = "com.saveourtool.diktat:diktat-runner:2.0.0" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. flexmark-all = "com.vladsch.flexmark:flexmark-all:0.64.8" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. freshmark = "com.diffplug.freshmark:freshmark:1.3.1" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. gherkin-utils = "io.cucumber:gherkin-utils:10.0.0" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. google-java-format = "com.google.googlejavaformat:google-java-format:1.30.0" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. gson = "com.google.code.gson:gson:2.14.0" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. json-simple = "org.json:json:20210307" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. ktfmt = "com.facebook:ktfmt:0.63" palantir-java-format = "com.palantir.javaformat:palantir-java-format:1.1.0" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. prince-of-space-core = "io.github.agustafson.princeofspace:prince-of-space-core:2.2.0" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. scalafmt-core = "org.scalameta:scalafmt-core_2.13:3.8.1" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. sortpom-sorter = "com.github.ekryd.sortpom:sortpom-sorter:4.0.0" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. tabletest-formatter-core = "org.tabletest:tabletest-formatter-core:1.1.2" +# When updating this version, remember to update CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md. zjsonpatch = "com.flipkart.zjsonpatch:zjsonpatch:0.4.16" rewrite-recipe-migrate-java = "org.openrewrite.recipe:rewrite-migrate-java:3.36.0" From 63265c53ee2bec4666ed6cf4e3c8f901a57cef95 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 15 Sep 2026 09:51:08 +0800 Subject: [PATCH 2/2] Add workflow to automatically update changelogs for Renovate PRs --- .github/scripts/update_renovate_changelogs.py | 182 ++++++++++++++++++ .github/workflows/renovate-changelog.yml | 41 ++++ 2 files changed, 223 insertions(+) create mode 100755 .github/scripts/update_renovate_changelogs.py create mode 100644 .github/workflows/renovate-changelog.yml diff --git a/.github/scripts/update_renovate_changelogs.py b/.github/scripts/update_renovate_changelogs.py new file mode 100755 index 0000000000..61c64f425c --- /dev/null +++ b/.github/scripts/update_renovate_changelogs.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +import argparse +import re +import subprocess +import sys +import tomllib +from pathlib import Path + +KEY_MAPPING = { + ("versions", "jackson"): "jackson", + ("versions", "ktlint"): "ktlint", + ("versions", "javaparser"): "javaparser", + ("libraries", "palantir-java-format-default"): "palantir-java-format", + ("libraries", "adocfmt"): "adocfmt", + ("libraries", "antlr4-formatter"): "antlr4-formatter", + ("libraries", "cleanthat-java"): "cleanthat", + ("libraries", "cool-rdf-formatter"): "cool-rdf-formatter", + ("libraries", "diktat-runner"): "diktat", + ("libraries", "flexmark-all"): "flexmark", + ("libraries", "freshmark"): "freshmark", + ("libraries", "gherkin-utils"): "gherkin-utils", + ("libraries", "google-java-format"): "google-java-format", + ("libraries", "gson"): "gson", + ("libraries", "json-simple"): "json-simple", + ("libraries", "ktfmt"): "ktfmt", + ("libraries", "prince-of-space-core"): "prince-of-space", + ("libraries", "scalafmt-core"): "scalafmt", + ("libraries", "sortpom-sorter"): "sortpom", + ("libraries", "tabletest-formatter-core"): "tabletest-formatter", + ("libraries", "zjsonpatch"): "zjsonpatch", +} + +CHANGELOG_FILES = [ + Path("CHANGES.md"), + Path("plugin-gradle/CHANGES.md"), + Path("plugin-maven/CHANGES.md"), +] + + +def extract_formatter_versions(toml_str: str) -> dict[str, str]: + data = tomllib.loads(toml_str) + versions = data.get("versions", {}) + libraries = data.get("libraries", {}) + result = {} + for (sec, key), tool_name in KEY_MAPPING.items(): + if sec == "versions": + if key in versions: + result[tool_name] = str(versions[key]) + elif sec == "libraries": + if key in libraries: + val = libraries[key] + if isinstance(val, str): + parts = val.split(":") + if len(parts) >= 3: + result[tool_name] = parts[-1] + elif isinstance(val, dict): + if "version" in val: + result[tool_name] = str(val["version"]) + elif "version.ref" in val and val["version.ref"] in versions: + result[tool_name] = str(versions[val["version.ref"]]) + return result + + +def insert_changelog_entries(content: str, entries: list[str]) -> str: + unreleased_match = re.search(r"(##\s*\[Unreleased\]\s*\n+)", content) + if not unreleased_match: + return content + + unreleased_start = unreleased_match.end() + next_release_match = re.search(r"\n##\s*\[", content[unreleased_start:]) + if next_release_match: + unreleased_end = unreleased_start + next_release_match.start() + unreleased_block = content[unreleased_start:unreleased_end] + after_block = content[unreleased_end:] + else: + unreleased_block = content[unreleased_start:] + after_block = "" + + new_entries = [e for e in entries if e not in unreleased_block] + if not new_entries: + return content + + entries_text = "\n".join(new_entries) + + changes_match = re.search(r"(###\s*Changes\s*\n)", unreleased_block) + if changes_match: + changes_header_end = changes_match.end() + # Find the end of ### Changes section (either next ### or next ## or end of block) + next_section_match = re.search(r"\n(###\s+\w+|##\s*\[)", unreleased_block[changes_header_end:]) + if next_section_match: + changes_end = changes_header_end + next_section_match.start() + changes_content = unreleased_block[changes_header_end:changes_end].rstrip() + rest = unreleased_block[changes_end:].lstrip("\n") + unreleased_block = ( + unreleased_block[:changes_header_end] + + (changes_content + "\n" if changes_content else "") + + entries_text + + "\n\n" + + rest + ) + else: + changes_content = unreleased_block[changes_header_end:].rstrip() + unreleased_block = ( + unreleased_block[:changes_header_end] + + (changes_content + "\n" if changes_content else "") + + entries_text + + "\n\n" + ) + else: + if unreleased_block.strip(): + unreleased_block = "### Changes\n" + entries_text + "\n\n" + unreleased_block.lstrip() + else: + unreleased_block = "### Changes\n" + entries_text + "\n\n" + + return content[:unreleased_start] + unreleased_block + after_block + + +def main() -> None: + parser = argparse.ArgumentParser(description="Update changelog files for Renovate version bumps.") + parser.add_argument("--base-ref", default="origin/main", help="Base ref or branch name to compare against") + parser.add_argument("--pr-number", required=True, help="Pull Request number") + parser.add_argument("--pr-url", required=True, help="Pull Request URL") + args = parser.parse_args() + + toml_path = Path("gradle/libs.versions.toml") + if not toml_path.exists(): + print(f"Error: {toml_path} does not exist.") + sys.exit(1) + + head_content = toml_path.read_text(encoding="utf-8") + + # Find the merge base commit between base_ref and HEAD so that only changes in this PR are considered + merge_base_proc = subprocess.run( + ["git", "merge-base", args.base_ref, "HEAD"], + capture_output=True, + text=True, + ) + if merge_base_proc.returncode == 0 and merge_base_proc.stdout.strip(): + compare_ref = merge_base_proc.stdout.strip() + else: + compare_ref = args.base_ref + + git_show_cmd = ["git", "show", f"{compare_ref}:gradle/libs.versions.toml"] + proc = subprocess.run(git_show_cmd, capture_output=True, text=True) + if proc.returncode != 0: + print(f"Warning: Failed to fetch base toml from {compare_ref}: {proc.stderr}") + sys.exit(0) + + base_content = proc.stdout + + base_versions = extract_formatter_versions(base_content) + head_versions = extract_formatter_versions(head_content) + + entries = [] + for tool_name, new_ver in head_versions.items(): + old_ver = base_versions.get(tool_name) + if old_ver and old_ver != new_ver: + entry = f"- Bump default `{tool_name}` version `{old_ver}` -> `{new_ver}`. ([#{args.pr_number}]({args.pr_url}))" + entries.append(entry) + + if not entries: + print("No formatter default versions changed in this branch.") + return + + print(f"Detected {len(entries)} formatter version update(s):") + for entry in entries: + print(f" {entry}") + + for changelog_file in CHANGELOG_FILES: + if not changelog_file.exists(): + continue + original = changelog_file.read_text(encoding="utf-8") + updated = insert_changelog_entries(original, entries) + if updated != original: + changelog_file.write_text(updated, encoding="utf-8") + print(f"Updated {changelog_file}") + else: + print(f"No changes needed for {changelog_file}") + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/renovate-changelog.yml b/.github/workflows/renovate-changelog.yml new file mode 100644 index 0000000000..3ecee946d8 --- /dev/null +++ b/.github/workflows/renovate-changelog.yml @@ -0,0 +1,41 @@ +name: Renovate Changelog Updater + +on: + pull_request: + types: [ opened, synchronize, reopened ] + paths: + - 'gradle/libs.versions.toml' + +jobs: + update-changelog: + name: Update Changelog + if: github.actor == 'renovate[bot]' || startsWith(github.head_ref, 'renovate/') + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: read + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ github.head_ref }} + fetch-depth: 0 + - uses: actions/setup-python@v7 + with: + python-version: "3.12" + - name: Update Changelogs + run: | + python3 .github/scripts/update_renovate_changelogs.py \ + --base-ref "origin/${{ github.base_ref }}" \ + --pr-number "${{ github.event.pull_request.number }}" \ + --pr-url "${{ github.event.pull_request.html_url }}" + - name: Commit and push changes + run: | + if [ -n "$(git status --porcelain CHANGES.md plugin-gradle/CHANGES.md plugin-maven/CHANGES.md)" ]; then + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add CHANGES.md plugin-gradle/CHANGES.md plugin-maven/CHANGES.md + git commit -m "Update changelogs for default formatter version bump (#${{ github.event.pull_request.number }})" + git push origin HEAD:${{ github.head_ref }} + else + echo "No changelog updates needed." + fi