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
+
1
36
import argparse
2
37
from pathlib import Path
3
38
import subprocess
8
43
)
9
44
VER_REPLACE = 'version = "%d.%d.%d%s" # auto'
10
45
COMPONENTS = ("major" , "minor" , "patch" , "rc" )
46
+ VERSION_LOG = re .compile (r"^## \[\d+\.\d+\.\d+(?:\-rc)?\d*\]" )
11
47
12
48
13
49
class Updater :
@@ -40,10 +76,34 @@ def replace(match: re.Match[str]) -> str:
40
76
return VER_REPLACE % (tuple (ver [:3 ]) + (rc_str ,))
41
77
42
78
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
+
43
102
def main ():
44
103
parser = argparse .ArgumentParser ()
45
104
parser .add_argument ("component" , default = "patch" , choices = COMPONENTS )
46
105
parser .parse_args (namespace = Updater )
106
+
47
107
cargo_path = Path ("Cargo.toml" )
48
108
doc = cargo_path .read_text (encoding = "utf-8" )
49
109
doc = VER_PATTERN .sub (Updater .replace , doc )
@@ -63,20 +123,31 @@ def main():
63
123
)
64
124
subprocess .run (["napi" , "version" ], cwd = "node-binding" , check = True )
65
125
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
+
67
130
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 )
69
133
try :
70
134
subprocess .run (["git" , "push" ], check = True )
71
135
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" )
74
146
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" )
76
149
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
80
151
81
152
82
153
if __name__ == "__main__" :
0 commit comments