summaryrefslogtreecommitdiff
path: root/tasks/generate.py
blob: 268b36fd6693b23c5a79244642d458690e8a278b (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
"""
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)