summaryrefslogtreecommitdiff
path: root/tasks/generate.py
blob: 398af70c9427a76ac21851bc4cd485b170e223e6 (plain)
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)