Completed
Pull Request — master (#58)
by Gonzalo
58s
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
    if issue_label_groups:
73
        new_filtered_issues = []
74
        grouped_filtered_issues = OrderedDict()
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
124
    # Set milestone or from tag
125
    if milestone and not since_tag:
126
        milestone_data = gh.milestone(milestone)
127
        milestone_number = milestone_data['number']
128
        closed_at = milestone_data['closed_at']
129
        version = milestone.replace('v', '')
130
    elif not milestone and since_tag:
131
        since = gh.tag(since_tag)['tagger']['date']
132
        if until_tag:
133
            until = gh.tag(until_tag)['tagger']['date']
134
            closed_at = until
135
136
    # This returns issues and pull requests
137
    issues = gh.issues(
138
        milestone=milestone_number,
139
        state='closed',
140
        since=since,
141
        until=until,
142
        branch=branch, )
143
144
    # Filter by regex if available
145
    filtered_prs = filter_prs_by_regex(issues, pr_label_regex)
146
    filtered_issues = filter_issues_by_regex(issues, issue_label_regex)
147
148
    # If issue label grouping, filter issues
149
    new_filtered_issues, issue_label_groups = filter_issue_label_groups(
150
        filtered_issues, issue_label_groups)
151
152
    return format_changelog(
153
        repo,
154
        new_filtered_issues,
155
        filtered_prs,
156
        version,
157
        closed_at=closed_at,
158
        output_format=output_format,
159
        template_file=template_file,
160
        issue_label_groups=issue_label_groups)
161
162
163
def format_changelog(repo,
164
                     issues,
165
                     prs,
166
                     version,
167
                     closed_at=None,
168
                     output_format='changelog',
169
                     output_file='CHANGELOG.temp',
170
                     template_file=None,
171
                     issue_label_groups=None):
172
    """Create changelog data."""
173
    # Header
174
    if not version:
175
        version = '<RELEASE_VERSION>'
176
177
    if closed_at:
178
        close_date = closed_at.split('T')[0]
179
    else:
180
        close_date = time.strftime("%Y/%m/%d")
181
182
    # Load template
183
    if template_file:
184
        filepath = template_file
185
    else:
186
        if issue_label_groups:
187
            if output_format == 'changelog':
188
                filepath = CHANGELOG_GROUPS_TEMPLATE_PATH
189
            else:
190
                filepath = RELEASE_GROUPS_TEMPLATE_PATH
191
        else:
192
            if output_format == 'changelog':
193
                filepath = CHANGELOG_TEMPLATE_PATH
194
            else:
195
                filepath = RELEASE_TEMPLATE_PATH
196
197
    with open(filepath) as f:
198
        data = f.read()
199
200
    repo_owner, repo_name = repo.split('/')
201
    template = Template(data)
202
    rendered = template.render(
203
        issues=issues,
204
        pull_requests=prs,
205
        version=version,
206
        close_date=close_date,
207
        repo_full_name=repo,
208
        repo_owner=repo_owner,
209
        repo_name=repo_name,
210
        issue_label_groups=issue_label_groups, )
211
212
    print('#' * 79)
213
    print(rendered)
214
    print('#' * 79)
215
216
    with open(output_file, 'w') as f:
217
        f.write(rendered)
218
219
    return rendered
220