11"""
22Changelog Modifier and Version Bumper for Cargo.toml and Changelog.md
33
4- This script automates the process of version bumping and changelog updates for Rust projects managed with Cargo.
5- It reads the version from the cargo.toml file, increments it based on the specified component (major, minor, or patch),
4+ This script automates the process of version bumping and changelog updates for Rust projects managed with Cargo.
5+ It reads the version from the cargo.toml file, increments it based on the specified component (major, minor, or patch),
66and updates both the cargo.toml and changelog.md files accordingly.
77
88It can also add PR entries to the UNRELEASED section of the changelog.
99
1010Usage:
1111 Version bumping:
1212 $ python modify_changelog.py bump_version [major|minor|patch]
13-
13+
1414 Adding PR entry:
1515 $ python modify_changelog.py update_changelog <number> <title>
1616
2020 major - Increments the major component of the version, sets minor and patch to 0
2121 minor - Increments the minor component of the version, sets patch to 0
2222 patch - Increments the patch component of the version
23-
23+
2424 update_changelog - Add a PR entry to the UNRELEASED section
2525 number - PR number
2626 title - PR title
@@ -59,20 +59,19 @@ def find_unreleased_section(lines):
5959 """Find the line number where UNRELEASED section starts and ends."""
6060 unreleased_start = None
6161 content_start = None
62-
62+
6363 for i , line in enumerate (lines ):
6464 if line .strip () == "## UNRELEASED" :
6565 unreleased_start = i
6666 continue
67-
67+
6868 if unreleased_start is not None and content_start is None :
6969 # Skip empty lines after ## UNRELEASED
7070 if line .strip () == "" :
7171 continue
72- else :
73- content_start = i
74- break
75-
72+ content_start = i
73+ break
74+
7675 return unreleased_start , content_start
7776
7877
@@ -87,35 +86,34 @@ def update_changelog_version(file_path: Path, new_version: str) -> None:
8786
8887def update_changelog_pr (file_path : Path , pr_number : str , pr_title : str , pr_url : str ) -> bool :
8988 """Update the changelog with the new PR entry. If entry exists, update it; otherwise add new entry."""
90-
9189 # Read the current changelog
92- with open (file_path , 'r' , encoding = ' utf-8' ) as f :
90+ with open (file_path , encoding = " utf-8" ) as f :
9391 lines = f .readlines ()
94-
92+
9593 # Find the UNRELEASED section
9694 unreleased_start , content_start = find_unreleased_section (lines )
97-
95+
9896 if unreleased_start is None :
9997 print ("ERROR: Could not find '## UNRELEASED' section in changelog" )
10098 return False
101-
99+
102100 if content_start is None :
103101 print ("ERROR: Could not find content start after UNRELEASED section" )
104102 return False
105-
103+
106104 # Create the new entry
107105 new_entry = f"- { pr_title } [#{ pr_number } ]({ pr_url } )\n "
108-
106+
109107 # Check if this PR entry already exists and update it if so
110108 existing_entry_index = None
111109 for i , line in enumerate (lines [content_start :], start = content_start ):
112110 if f"[#{ pr_number } ]" in line :
113111 existing_entry_index = i
114112 break
115113 # Stop checking when we reach the next section
116- if line .startswith ("## " ) and not line .strip () = = "## UNRELEASED" :
114+ if line .startswith ("## " ) and line .strip () ! = "## UNRELEASED" :
117115 break
118-
116+
119117 if existing_entry_index is not None :
120118 # Update existing entry
121119 lines [existing_entry_index ] = new_entry
@@ -124,11 +122,11 @@ def update_changelog_pr(file_path: Path, pr_number: str, pr_title: str, pr_url:
124122 # Insert the new entry at the beginning of the unreleased content
125123 lines .insert (content_start , new_entry )
126124 print (f"Added changelog entry for PR #{ pr_number } : { pr_title } " )
127-
125+
128126 # Write the updated changelog
129- with open (file_path , 'w' , encoding = ' utf-8' ) as f :
127+ with open (file_path , "w" , encoding = " utf-8" ) as f :
130128 f .writelines (lines )
131-
129+
132130 return True
133131
134132
@@ -141,7 +139,7 @@ def handle_bump_version(args):
141139 if not cargo_path .exists ():
142140 print ("ERROR: Cargo.toml not found." )
143141 sys .exit (1 )
144-
142+
145143 if not changelog_path .exists ():
146144 print ("ERROR: Changelog file not found." )
147145 sys .exit (1 )
@@ -164,49 +162,47 @@ def handle_update_changelog(args):
164162 """Handle update changelog subcommand."""
165163 pr_number = args .number
166164 pr_title = args .title
167-
165+
168166 # Construct PR URL from repository info and PR number
169167 # Default to the egglog-python repository
170168 pr_url = f"https://github.com/egraphs-good/egglog-python/pull/{ pr_number } "
171-
172- changelog_path = Path (getattr (args , ' changelog_path' , ' docs/changelog.md' ))
173-
169+
170+ changelog_path = Path (getattr (args , " changelog_path" , " docs/changelog.md" ))
171+
174172 if not changelog_path .exists ():
175173 print (f"ERROR: Changelog file not found: { changelog_path } " )
176174 sys .exit (1 )
177-
175+
178176 success = update_changelog_pr (changelog_path , pr_number , pr_title , pr_url )
179177 if not success :
180178 sys .exit (1 )
181179
182180
183181def main ():
184- parser = argparse .ArgumentParser (description = ' Changelog modifier and version bumper' )
185- subparsers = parser .add_subparsers (dest = ' command' , help = ' Available commands' )
186-
182+ parser = argparse .ArgumentParser (description = " Changelog modifier and version bumper" )
183+ subparsers = parser .add_subparsers (dest = " command" , help = " Available commands" )
184+
187185 # Bump version subcommand
188- bump_parser = subparsers .add_parser ('bump_version' , help = 'Bump version and update changelog' )
189- bump_parser .add_argument ('bump_type' , choices = ['major' , 'minor' , 'patch' ],
190- help = 'Type of version bump' )
191-
186+ bump_parser = subparsers .add_parser ("bump_version" , help = "Bump version and update changelog" )
187+ bump_parser .add_argument ("bump_type" , choices = ["major" , "minor" , "patch" ], help = "Type of version bump" )
188+
192189 # Update changelog subcommand
193- changelog_parser = subparsers .add_parser ('update_changelog' , help = 'Add PR entry to changelog' )
194- changelog_parser .add_argument ('number' , help = 'Pull request number' )
195- changelog_parser .add_argument ('title' , help = 'Pull request title' )
196- changelog_parser .add_argument ('--changelog-path' , default = 'docs/changelog.md' ,
197- help = 'Path to changelog file' )
198-
190+ changelog_parser = subparsers .add_parser ("update_changelog" , help = "Add PR entry to changelog" )
191+ changelog_parser .add_argument ("number" , help = "Pull request number" )
192+ changelog_parser .add_argument ("title" , help = "Pull request title" )
193+ changelog_parser .add_argument ("--changelog-path" , default = "docs/changelog.md" , help = "Path to changelog file" )
194+
199195 args = parser .parse_args ()
200-
196+
201197 if not args .command :
202198 parser .print_help ()
203199 sys .exit (1 )
204-
205- if args .command == ' bump_version' :
200+
201+ if args .command == " bump_version" :
206202 handle_bump_version (args )
207- elif args .command == ' update_changelog' :
203+ elif args .command == " update_changelog" :
208204 handle_update_changelog (args )
209205
210206
211207if __name__ == "__main__" :
212- main ()
208+ main ()
0 commit comments