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
|
"""
Invoke development tasks.
"""
from pathlib import Path
from subprocess import check_output, check_call
import invoke
@invoke.task(help={"version": "version being released"})
def announce(ctx, version):
"""Generates a new release announcement entry in the docs."""
# Get our list of authors
stdout = check_output(["git", "describe", "--abbrev=0", "--tags"])
stdout = stdout.decode("utf-8")
last_version = stdout.strip()
stdout = check_output(
["git", "log", "{}..HEAD".format(last_version), "--format=%aN"]
)
stdout = stdout.decode("utf-8")
contributors = set(stdout.splitlines())
template_name = "release.minor.rst" if version.endswith(
".0"
) else "release.patch.rst"
template_text = Path(__file__).parent.joinpath(template_name).read_text(
encoding="UTF-8"
)
contributors_text = "\n".join(
"* {}".format(name) for name in sorted(contributors)
) + "\n"
text = template_text.format(version=version, contributors=contributors_text)
target = Path(__file__).parent.joinpath(
"../doc/en/announce/release-{}.rst".format(version)
)
target.write_text(text, encoding="UTF-8")
print("[generate.announce] Generated {}".format(target.name))
# Update index with the new release entry
index_path = Path(__file__).parent.joinpath("../doc/en/announce/index.rst")
lines = index_path.read_text(encoding="UTF-8").splitlines()
indent = " "
for index, line in enumerate(lines):
if line.startswith("{}release-".format(indent)):
new_line = indent + target.stem
if line != new_line:
lines.insert(index, new_line)
index_path.write_text("\n".join(lines) + "\n", encoding="UTF-8")
print("[generate.announce] Updated {}".format(index_path.name))
else:
print(
"[generate.announce] Skip {} (already contains release)".format(
index_path.name
)
)
break
check_call(["git", "add", str(target)])
@invoke.task()
def regen(ctx):
"""Call regendoc tool to update examples and pytest output in the docs."""
print("[generate.regen] Updating docs")
check_call(["tox", "-e", "regen"])
@invoke.task()
def make_tag(ctx, version):
"""Create a new, local tag for the release, only if the repository is clean."""
from git import Repo
repo = Repo(".")
if repo.is_dirty():
print("Current repository is dirty. Please commit any changes and try again.")
raise invoke.Exit(code=2)
tag_names = [x.name for x in repo.tags]
if version in tag_names:
print("[generate.make_tag] Delete existing tag {}".format(version))
repo.delete_tag(version)
print("[generate.make_tag] Create tag {}".format(version))
repo.create_tag(version)
@invoke.task(help={"version": "version being released"})
def pre_release(ctx, version):
"""Generates new docs, release announcements and creates a local tag."""
announce(ctx, version)
regen(ctx)
changelog(ctx, version, write_out=True)
msg = "Preparing release version {}".format(version)
check_call(["git", "commit", "-a", "-m", msg])
make_tag(ctx, version)
print()
print("[generate.pre_release] Please push your branch and open a PR.")
@invoke.task(
help={
"version": "version being released",
"write_out": "write changes to the actual changelog",
}
)
def changelog(ctx, version, write_out=False):
if write_out:
addopts = []
else:
addopts = ["--draft"]
check_call(["towncrier", "--yes", "--version", version] + addopts)
|