-
Notifications
You must be signed in to change notification settings - Fork 8
/
finish_release.py
127 lines (108 loc) · 4.52 KB
/
finish_release.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"""Release script to finish the release"""
import os
import re
from datetime import datetime
from async_subprocess import (
check_call,
check_output,
)
from exception import VersionMismatchException
from lib import get_default_branch
from release import (
init_working_dir,
validate_dependencies,
)
async def merge_release_candidate(*, root):
"""Merge release-candidate into release"""
await check_call(["git", "checkout", "release"], cwd=root)
await check_call(["git", "merge", "release-candidate", "--no-edit"], cwd=root)
await check_call(["git", "push"], cwd=root)
async def check_release_tag(version, *, root):
"""Check release version number"""
await check_call(["git", "checkout", "release-candidate"], cwd=root)
log_output = await check_output(["git", "log", "-1", "--pretty=%B"], cwd=root)
commit_name = log_output.decode().strip()
if commit_name != f"Release {version}":
raise VersionMismatchException(
f"Commit name {commit_name} does not match tag number {version}"
)
async def tag_release(version, *, root):
"""Add git tag for release"""
await check_call(
["git", "tag", "-a", "-m", f"Release {version}", f"v{version}"],
cwd=root,
)
await check_call(["git", "push", "--follow-tags"], cwd=root)
async def set_release_date(version, timezone, *, root):
"""Sets the release date(s) in RELEASE.rst for any versions missing it"""
release_filename = os.path.join(root, "RELEASE.rst")
if not os.path.isfile(release_filename):
return
date_format = "%B %d, %Y"
await check_call(["git", "fetch", "--tags"], cwd=root)
await check_call(["git", "checkout", "release-candidate"], cwd=root)
with open(release_filename, "r", encoding="utf-8") as f:
existing_note_lines = f.readlines()
with open(release_filename, "w", encoding="utf-8") as f:
for line in existing_note_lines:
if line.startswith("Version ") and "Released" not in line:
version_match = re.search(r"[0-9\.]+", line)
if version_match:
version_line = version_match.group(0)
if version_line == version:
localtime = datetime.now().strftime(date_format)
else:
version_output = await check_output(
[
"git",
"log",
"-1",
"--format=%ai",
f"v{version_line}",
],
cwd=root,
)
version_date = version_output.rstrip()
localtime = (
datetime.strptime(
version_date.decode("utf-8"), "%Y-%m-%d %H:%M:%S %z"
)
.astimezone(timezone)
.strftime(date_format)
)
line = f"Version {version_line} (Released {localtime})\n"
f.write(line)
await check_call(
[
"git",
"commit",
"-q",
release_filename,
"-m",
f"Release date for {version}",
],
cwd=root,
)
async def merge_release(*, root):
"""Merge release to master"""
default_branch = await get_default_branch(root)
await check_call(["git", "checkout", "-q", default_branch], cwd=root)
await check_call(["git", "pull"], cwd=root)
await check_call(["git", "merge", "release", "--no-edit"], cwd=root)
await check_call(["git", "push"], cwd=root)
async def finish_release(*, github_access_token, repo_info, version, timezone):
"""
Merge release to master and deploy to production
Args:
github_access_token (str): Github access token
repo_info (RepoInfo): The info of the project being released
version (str): The new version of the release
timezone (any): Some timezone object to set the proper release datetime string
"""
await validate_dependencies()
async with init_working_dir(github_access_token, repo_info.repo_url) as working_dir:
await check_release_tag(version, root=working_dir)
await set_release_date(version, timezone, root=working_dir)
await merge_release_candidate(root=working_dir)
await tag_release(version, root=working_dir)
await merge_release(root=working_dir)