Completed
Push — master ( 00af05...860b51 )
by Gonzalo
7s
created

format_changelog()   C

Complexity

Conditions 9

Size

Total Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 16
Bugs 2 Features 1
Metric Value
cc 9
c 16
b 2
f 1
dl 0
loc 57
rs 5.2182

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
# -*- coding: utf-8 -*-
2
# -----------------------------------------------------------------------------
3
# Copyright (c) The Spyder Development Team
4
#
5
# Licensed under the terms of the MIT License
6
# (See LICENSE.txt for details)
7
# -----------------------------------------------------------------------------
8
"""Loghub filter and formatter."""
9
10
# yapf: disable
11
12
# Standard library imports
13
from collections import OrderedDict
14
import re
15
import time
16
17
# Third party imports
18
from jinja2 import Template
19
20
# Local imports
21
from loghub.core.repo import GitHubRepo
22
from loghub.templates import (CHANGELOG_GROUPS_TEMPLATE_PATH,
23
                              CHANGELOG_TEMPLATE_PATH,
24
                              RELEASE_GROUPS_TEMPLATE_PATH,
25
                              RELEASE_TEMPLATE_PATH)
26
27
28
# yapf: enable
29
30
31
def filter_prs_by_regex(issues, pr_label_regex):
32
    """Filter prs by issue regex."""
33
    filtered_prs = []
34
    pr_pattern = re.compile(pr_label_regex)
35
36
    for issue in issues:
37
        is_pr = bool(issue.get('pull_request'))
38
        labels = ' '.join(issue.get('loghub_label_names'))
39
40
        if is_pr and pr_label_regex:
41
            pr_valid = bool(pr_pattern.search(labels))
42
            if pr_valid:
43
                filtered_prs.append(issue)
44
        if is_pr and not pr_label_regex:
45
            filtered_prs.append(issue)
46
47
    return filtered_prs
48
49
50
def filter_issues_by_regex(issues, issue_label_regex):
51
    """Filter issues by issue regex."""
52
    filtered_issues = []
53
    issue_pattern = re.compile(issue_label_regex)
54
55
    for issue in issues:
56
        is_pr = bool(issue.get('pull_request'))
57
        is_issue = not is_pr
58
        labels = ' '.join(issue.get('loghub_label_names'))
59
60
        if is_issue and issue_label_regex:
61
            issue_valid = bool(issue_pattern.search(labels))
62
            if issue_valid:
63
                filtered_issues.append(issue)
64
        elif is_issue and not issue_label_regex:
65
            filtered_issues.append(issue)
66
67
    return filtered_issues
68
69
70
def filter_issue_label_groups(issues, issue_label_groups):
71
    """Filter issues by the label groups."""
72
    grouped_filtered_issues = OrderedDict()
73
    if issue_label_groups:
74
        new_filtered_issues = []
75
        for label_group_dic in issue_label_groups:
76
            grouped_filtered_issues[label_group_dic['name']] = []
77
78
        for issue in issues:
79
            for label_group_dic in issue_label_groups:
80
                labels = issue.get('loghub_label_names')
81
                label = label_group_dic['label']
82
                name = label_group_dic['name']
83
                if label in labels:
84
                    grouped_filtered_issues[name].append(issue)
85
                    new_filtered_issues.append(issue)
86
87
        # Remove any empty groups
88
        for group, grouped_issues in grouped_filtered_issues.copy().items():
89
            if not grouped_issues:
90
                grouped_filtered_issues.pop(group)
91
    else:
92
        new_filtered_issues = issues
93
94
    return new_filtered_issues, grouped_filtered_issues
95
96
97
def create_changelog(repo=None,
98
                     username=None,
99
                     password=None,
100
                     token=None,
101
                     milestone=None,
102
                     since_tag=None,
103
                     until_tag=None,
104
                     branch=None,
105
                     output_format='changelog',
106
                     issue_label_regex='',
107
                     pr_label_regex='',
108
                     template_file=None,
109
                     issue_label_groups=None):
110
    """Create changelog data."""
111
    # Instantiate Github API
112
    gh = GitHubRepo(
113
        username=username,
114
        password=password,
115
        token=token,
116
        repo=repo, )
117
118
    version = until_tag or None
119
    milestone_number = None
120
    closed_at = None
121
    since = None
122
    until = None
123
    version_tag_prefix = 'v'
124
125
    # Set milestone or from tag
126
    if milestone and not since_tag:
127
        milestone_data = gh.milestone(milestone)
128
        milestone_number = milestone_data['number']
129
        closed_at = milestone_data['closed_at']
130
        version = milestone
131
132
        if version.startswith(version_tag_prefix):
133
            version = version[len(version_tag_prefix):]
134
135
    elif not milestone and since_tag:
136
        since = gh.tag(since_tag)['tagger']['date']
137
        if until_tag:
138
            until = gh.tag(until_tag)['tagger']['date']
139
            closed_at = until
140
141
    # This returns issues and pull requests
142
    issues = gh.issues(
143
        milestone=milestone_number,
144
        state='closed',
145
        since=since,
146
        until=until,
147
        branch=branch, )
148
149
    # Filter by regex if available
150
    filtered_prs = filter_prs_by_regex(issues, pr_label_regex)
151
    filtered_issues = filter_issues_by_regex(issues, issue_label_regex)
152
153
    # If issue label grouping, filter issues
154
    new_filtered_issues, issue_label_groups = filter_issue_label_groups(
155
        filtered_issues, issue_label_groups)
156
157
    return format_changelog(
158
        repo,
159
        new_filtered_issues,
160
        filtered_prs,
161
        version,
162
        closed_at=closed_at,
163
        output_format=output_format,
164
        template_file=template_file,
165
        issue_label_groups=issue_label_groups)
166
167
168
def format_changelog(repo,
169
                     issues,
170
                     prs,
171
                     version,
172
                     closed_at=None,
173
                     output_format='changelog',
174
                     output_file='CHANGELOG.temp',
175
                     template_file=None,
176
                     issue_label_groups=None):
177
    """Create changelog data."""
178
    # Header
179
    if not version:
180
        version = '<RELEASE_VERSION>'
181
182
    if closed_at:
183
        close_date = closed_at.split('T')[0]
184
    else:
185
        close_date = time.strftime("%Y/%m/%d")
186
187
    # Load template
188
    if template_file:
189
        filepath = template_file
190
    else:
191
        if issue_label_groups:
192
            if output_format == 'changelog':
193
                filepath = CHANGELOG_GROUPS_TEMPLATE_PATH
194
            else:
195
                filepath = RELEASE_GROUPS_TEMPLATE_PATH
196
        else:
197
            if output_format == 'changelog':
198
                filepath = CHANGELOG_TEMPLATE_PATH
199
            else:
200
                filepath = RELEASE_TEMPLATE_PATH
201
202
    with open(filepath) as f:
203
        data = f.read()
204
205
    repo_owner, repo_name = repo.split('/')
206
    template = Template(data)
207
    rendered = template.render(
208
        issues=issues,
209
        pull_requests=prs,
210
        version=version,
211
        close_date=close_date,
212
        repo_full_name=repo,
213
        repo_owner=repo_owner,
214
        repo_name=repo_name,
215
        issue_label_groups=issue_label_groups, )
216
217
    print('#' * 79)
218
    print(rendered)
219
    print('#' * 79)
220
221
    with open(output_file, 'w') as f:
222
        f.write(rendered)
223
224
    return rendered
225