1
+ """This script automated 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) installed
8
+ to bump node-binding versions.
9
+
10
+ 2. Updates the CHANGELOG.md
11
+
12
+ Requires `git-cliff` installed (see https://git-cliff.org)
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` installed (see https://cli.github.com) to create the release and
24
+ 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 (rb"^## \[\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 = ("" , b"" )
81
+ log_file = Path (__file__ ).parent .parent .parent / "CHANGELOG.md"
82
+ tag_buf = f"[{ tag } ]" .encode (encoding = "utf-8" )
83
+ with open (str (log_file ), "rb" ) as log :
84
+ found_notes = False
85
+ for line in log .readlines ():
86
+ matched = VERSION_LOG .match (line )
87
+ if matched is not None :
88
+ if tag_buf in matched .group (0 ):
89
+ title = tag + line [matched .end () :].decode (encoding = "utf-8" )
90
+ found_notes = True
91
+ else :
92
+ found_notes = False
93
+ elif line .startswith (b"[unreleased]: " ) and found_notes :
94
+ found_notes = False
95
+ elif found_notes :
96
+ buf += line
97
+ elif line .startswith (tag_buf + b": " ):
98
+ buf += line .replace (tag_buf , b"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,34 @@ 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
136
raise RuntimeError ("Failed to push commit for version bump" ) from exc
73
- print ("Pushed commit to 'bump version to" , tag , "'" )
74
- try :
75
- subprocess .run (["git" , "tag" , tag ], check = True )
76
- 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" )
137
+
138
+ title , notes = get_release_notes ()
139
+ print ("Pushed commit to 'Bump version to" , tag , "'" )
140
+ gh_cmd = [
141
+ "gh" ,
142
+ "release" ,
143
+ "create" ,
144
+ tag ,
145
+ "--title" ,
146
+ title ,
147
+ "--notes" ,
148
+ notes .decode ("utf-8" ),
149
+ ]
150
+ if Updater .component == "rc" :
151
+ gh_cmd .append ("--prerelease" )
152
+ subprocess .run (gh_cmd , check = True )
153
+ print ("Created tag" , tag , "and corresponding GitHub Release" )
80
154
81
155
82
156
if __name__ == "__main__" :
0 commit comments