Completed
Pull Request — master (#127)
by Michael
11:23 queued 10:49
created

Release   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 38
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 38
ccs 19
cts 19
cp 1
rs 10
wmc 8

3 Methods

Rating   Name   Duplication   Size   Complexity  
A title() 0 6 2
A release_note_filename() 0 6 2
A generate_notes() 0 12 4
1 3
import re
2 3
import textwrap
3 3
from configparser import RawConfigParser
4 3
from enum import Enum
5 3
from pathlib import Path
6
7 3
import attr
8 3
import click
9
10
11 3
class ReleaseType(str, Enum):
12 3
    NO_CHANGE = 'no-changes'
13 3
    BREAKING_CHANGE = 'breaking'
14 3
    FEATURE = 'feature'
15 3
    FIX = 'fix'
16
17
18 3
@attr.s
19 3
class Release(object):
20 3
    release_date = attr.ib()
21 3
    version = attr.ib()
22 3
    description = attr.ib(default=attr.Factory(str))
23 3
    name = attr.ib(default=attr.Factory(str))
24 3
    notes = attr.ib(default=attr.Factory(dict))
25 3
    release_file_path = attr.ib(default='')
26
27 3
    bumpversion_part = attr.ib(default=None)
28 3
    release_type = attr.ib(default=None)
29
30 3
    @property
31
    def title(self):
32 3
        return '{version} ({release_date})'.format(
33
            version=self.version,
34
            release_date=self.release_date
35
        ) + ((' ' + self.name) if self.name else '')
36
37 3
    @property
38
    def release_note_filename(self):
39 3
        return '{version}-{release_date}'.format(
40
            version=self.version,
41
            release_date=self.release_date
42
        ) + (('-' + self.name) if self.name else '')
43
44 3
    @classmethod
45
    def generate_notes(cls, project_labels, pull_requests_since_latest_version):
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (80/79).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
46 3
        for label, properties in project_labels.items():
47 3
            pull_requests_with_label = [
48
                pull_request
49
                for pull_request in pull_requests_since_latest_version
50
                if label in pull_request.label_names
51
            ]
52
53 3
            project_labels[label]['pull_requests'] = pull_requests_with_label
54
55 3
        return project_labels
56
57
58 3
@attr.s
59 3
class BumpVersion(object):
60 3
    DRAFT_OPTIONS = [
61
        '--dry-run', '--verbose',
62
        '--no-commit', '--no-tag',
63
        '--allow-dirty',
64
    ]
65 3
    STAGE_OPTIONS = [
66
        '--verbose', '--allow-dirty',
67
        '--no-commit', '--no-tag',
68
    ]
69
70 3
    current_version = attr.ib()
71 3
    version_files_to_replace = attr.ib(default=attr.Factory(list))
72
73 3
    @classmethod
74
    def load(cls, latest_version):
75
        # TODO: look in other supported bumpversion config locations
76 3
        bumpversion = None
77 3
        bumpversion_config_path = Path('.bumpversion.cfg')
78 3
        if not bumpversion_config_path.exists():
79 3
            user_supplied_versioned_file_paths = []
80
81 3
            version_file_path_answer = None
82 3
            input_terminator = '.'
83 3
            while not version_file_path_answer == input_terminator:
84 3
                version_file_path_answer = click.prompt(
85
                    'Enter a path to a file that contains a version number '
86
                    "(enter a path of '.' when you're done selecting files)",
87
                    type=click.Path(
88
                        exists=True,
89
                        dir_okay=True,
90
                        file_okay=True,
91
                        readable=True
92
                    )
93
                )
94
95 3
                if version_file_path_answer != input_terminator:
96 3
                    user_supplied_versioned_file_paths.append(version_file_path_answer)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (87/79).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
97
98 3
            bumpversion = cls(
99
                current_version=latest_version,
100
                version_files_to_replace=user_supplied_versioned_file_paths,
101
            )
102 3
            bumpversion.write_to_file(bumpversion_config_path)
103
104 3
        return bumpversion
105
106 3
    @classmethod
107 3
    def read_from_file(cls, config_path: Path):
108 3
        config = RawConfigParser('')
109 3
        config.readfp(config_path.open('rt', encoding='utf-8'))
110
111 3
        current_version = config.get("bumpversion", 'current_version')
112
113 3
        filenames = []
114 3
        for section_name in config.sections():
115
116 3
            section_name_match = re.compile("^bumpversion:(file|part):(.+)").match(section_name)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (96/79).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
117
118 3
            if not section_name_match:
119 3
                continue
120
121 3
            section_prefix, section_value = section_name_match.groups()
122
123 3
            if section_prefix == "file":
124 3
                filenames.append(section_value)
125
126 3
        return cls(
127
            current_version=current_version,
128
            version_files_to_replace=filenames,
129
        )
130
131 3
    def write_to_file(self, config_path: Path):
132 3
        bumpversion_cfg = textwrap.dedent(
133
            """\
134
            [bumpversion]
135
            current_version = {current_version}
136
137
            """
138
        ).format(**attr.asdict(self))
139
140 3
        bumpversion_files = '\n\n'.join([
141
            '[bumpversion:file:{}]'.format(file_name)
142
            for file_name in self.version_files_to_replace
143
        ])
144
145 3
        config_path.write_text(
146
            bumpversion_cfg + bumpversion_files
147
        )
148