1+ """This script automates the release process for all of the packages in this repository.
2+ In order, this script does the following:
3+
4+ 1. Bump version number in manifest files according to given required arg (see `--help`).
5+ This alters the Cargo.toml in repo root and the package.json files in node-binding.
6+
7+ Requires `yarn` (see https://yarnpkg.com) and `napi` (see https://napi.rs) to be
8+ installed to bump node-binding versions.
9+
10+ 2. Updates the CHANGELOG.md
11+
12+ Requires `git-cliff` (see https://git-cliff.org) to be installed
13+ to regenerate the change logs from git history.
14+
15+ NOTE: `git cliff` uses GITHUB_TOKEN env var to access GitHub's REST API for
16+ fetching certain data (like PR labels and commit author's username).
17+
18+ 3. Pushes the changes from above 2 steps to remote
19+
20+ 4. Creates a GitHub Release and uses the section from the CHANGELOG about the new tag
21+ as a release description.
22+
23+ Requires `gh-cli` (see https://cli.github.com) to be installed to create the release
24+ and push the tag.
25+
26+ NOTE: This step also tags the commit from step 3.
27+ When a tag is pushed to the remote, the CI builds are triggered and
28+
29+ - release assets are uploaded to the Github Release corresponding to the new tag
30+ - packages are published for npm, pip, and cargo
31+
32+ NOTE: In a CI run, the GH_TOKEN env var to authenticate access.
33+ Locally, you can use `gh login` to interactively authenticate the user account.
34+ """
35+
136import argparse
237from pathlib import Path
338import subprocess
843)
944VER_REPLACE = 'version = "%d.%d.%d%s" # auto'
1045COMPONENTS = ("major" , "minor" , "patch" , "rc" )
46+ VERSION_LOG = re .compile (r"^## \[\d+\.\d+\.\d+(?:\-rc)?\d*\]" )
1147
1248
1349class Updater :
@@ -40,10 +76,34 @@ def replace(match: re.Match[str]) -> str:
4076 return VER_REPLACE % (tuple (ver [:3 ]) + (rc_str ,))
4177
4278
79+ def get_release_notes (tag : str = Updater .new_version ):
80+ title , buf = "" , ""
81+ log_file = Path (__file__ ).parent .parent .parent / "CHANGELOG.md"
82+ tag_pattern = f"[{ tag } ]"
83+ with open (str (log_file ), "r" , encoding = "utf-8" ) as logs :
84+ found_notes = False
85+ for line in logs :
86+ matched = VERSION_LOG .match (line )
87+ if matched is not None :
88+ if tag_pattern in matched .group (0 ):
89+ title = tag + line [matched .end () :]
90+ found_notes = True
91+ else :
92+ found_notes = False
93+ elif line .startswith ("[unreleased]: " ) and found_notes :
94+ found_notes = False
95+ elif found_notes :
96+ buf += line
97+ elif line .startswith (tag_pattern + ": " ):
98+ buf += line .replace (tag_pattern , "Full commit diff" , 1 )
99+ return title .rstrip (), buf .strip ()
100+
101+
43102def main ():
44103 parser = argparse .ArgumentParser ()
45104 parser .add_argument ("component" , default = "patch" , choices = COMPONENTS )
46105 parser .parse_args (namespace = Updater )
106+
47107 cargo_path = Path ("Cargo.toml" )
48108 doc = cargo_path .read_text (encoding = "utf-8" )
49109 doc = VER_PATTERN .sub (Updater .replace , doc )
@@ -63,20 +123,31 @@ def main():
63123 )
64124 subprocess .run (["napi" , "version" ], cwd = "node-binding" , check = True )
65125 print ("Updated version in node-binding/**package.json" )
66- tag = "v" + Updater .new_version
126+
127+ subprocess .run (["git" , "cliff" , "--tag" , Updater .new_version ], check = True )
128+ print ("Updated CHANGELOG.md" )
129+
67130 subprocess .run (["git" , "add" , "--all" ], check = True )
68- subprocess .run (["git" , "commit" , "-m" , f"bump version to { tag } " ], check = True )
131+ tag = "v" + Updater .new_version
132+ subprocess .run (["git" , "commit" , "-m" , f"Bump version to { tag } " ], check = True )
69133 try :
70134 subprocess .run (["git" , "push" ], check = True )
71135 except subprocess .CalledProcessError as exc :
72- raise RuntimeError ("Failed to push commit for version bump" ) from exc
73- print ("Pushed commit to 'bump version to" , tag , "'" )
136+ raise RuntimeError (
137+ """Failed to push commit for version bump. Please ensure that
138+ - You have the necessary permissions and are authenticated properly.
139+ - All other commits on the branch have ben pushed already."""
140+ ) from exc
141+ title , notes = get_release_notes ()
142+ print ("Pushed commit to 'Bump version to" , tag , "'" )
143+ gh_cmd = ["gh" , "release" , "create" , tag , "--title" , title , "--notes" , notes ]
144+ if Updater .component == "rc" :
145+ gh_cmd .append ("--prerelease" )
74146 try :
75- subprocess .run (["git" , "tag" , tag ], check = True )
147+ subprocess .run (gh_cmd , check = True )
148+ print ("Created tag" , tag , "and corresponding GitHub Release" )
76149 except subprocess .CalledProcessError as exc :
77- raise RuntimeError ("Failed to create tag for commit" ) from exc
78- print ("Created tag" , tag )
79- print (f"Use 'git push origin refs/tags/{ tag } ' to publish a release" )
150+ raise RuntimeError ("Failed to create GitHub Release" ) from exc
80151
81152
82153if __name__ == "__main__" :
0 commit comments