Completed
Pull Request — master (#120)
by Michael
13:50 queued 13:15
created

load_project_settings()   B

Complexity

Conditions 6

Size

Total Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 6.0026

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
c 2
b 0
f 0
dl 0
loc 63
ccs 23
cts 24
cp 0.9583
crap 6.0026
rs 7.7105

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 3
import textwrap
2 3
from os.path import exists, expanduser, expandvars, join, curdir
3 3
import io
4 3
import os
5 3
import sys
6
7 3
import click
0 ignored issues
show
Configuration introduced by
The import click could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
8 3
from pathlib import Path
9
10 3
import toml
0 ignored issues
show
Configuration introduced by
The import toml could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
11 3
import attr
0 ignored issues
show
Configuration introduced by
The import attr could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
12
13 3
import changes
14 3
from changes.models import GitRepository
15 3
from .commands import info, note
16
17
18 3
AUTH_TOKEN_ENVVAR = 'GITHUB_AUTH_TOKEN'
19
20
# via https://github.com/jakubroztocil/httpie/blob/6bdfc7a/httpie/config.py#L9
21 3
IS_WINDOWS = 'win32' in str(sys.platform).lower()
22 3
DEFAULT_CONFIG_FILE = str(os.environ.get(
23
    'CHANGES_CONFIG_FILE',
24
    expanduser('~/.changes') if not IS_WINDOWS else
25
    expandvars(r'%APPDATA%\\.changes')
26
))
27
28 3
PROJECT_CONFIG_FILE = '.changes.toml'
29 3
DEFAULT_RELEASES_DIRECTORY = 'docs/releases'
30
31
32 3
@attr.s
33 3
class Changes(object):
34 3
    auth_token = attr.ib()
35
36
37 3
def load_settings():
38 3
    tool_config_path = Path(str(os.environ.get(
39
        'CHANGES_CONFIG_FILE',
40
        expanduser('~/.changes') if not IS_WINDOWS else
41
        expandvars(r'%APPDATA%\\.changes')
42
    )))
43
44 3
    tool_settings = None
45 3
    if tool_config_path.exists():
46
        tool_settings = Changes(
47
            **(toml.load(tool_config_path.open())['changes'])
48
        )
49
50 3
    if not (tool_settings and tool_settings.auth_token):
51
        # prompt for auth token
52 3
        auth_token = os.environ.get(AUTH_TOKEN_ENVVAR)
53 3
        if auth_token:
54 3
            info('Found Github Auth Token in the environment')
55
56 3
        while not auth_token:
57 3
            info('No auth token found, asking for it')
58
            # to interact with the Git*H*ub API
59 3
            note('You need a Github Auth Token for changes to create a release.')
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (81/79).

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

Loading history...
60 3
            click.pause('Press [enter] to launch the GitHub "New personal access '
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (82/79).

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

Loading history...
61
                        'token" page, to create a token for changes.')
62 3
            click.launch('https://github.com/settings/tokens/new')
63 3
            auth_token = click.prompt('Enter your changes token')
64
65 3
        if not tool_settings:
66 3
            tool_settings = Changes(auth_token=auth_token)
67
68 3
        tool_config_path.write_text(
0 ignored issues
show
Bug introduced by
The Instance of Path does not seem to have a member named write_text.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
69
            toml.dumps({
70
                'changes': attr.asdict(tool_settings)
71
            })
72
        )
73
74 3
    return tool_settings
75
76
77 3
@attr.s
78 3
class Project(object):
79 3
    releases_directory = attr.ib()
80 3
    repository = attr.ib(default=None)
81 3
    bumpversion = attr.ib(default=None)
82 3
    towncrier = attr.ib(default=None)
83
84 3
    @property
85
    def bumpversion_configured(self):
86
        return isinstance(self.bumpversion, BumpVersion)
87
88 3
    @property
89
    def towncrier_configured(self):
90
        return isinstance(self.towncrier, TownCrier)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'TownCrier'
Loading history...
91
92
93 3
@attr.s
94 3
class BumpVersion(object):
95 3
    DRAFT_OPTIONS = [
96
        '--dry-run', '--verbose',
97
        '--no-commit', '--no-tag',
98
        '--allow-dirty',
99
    ]
100 3
    STAGE_OPTIONS = [
101
        '--verbose',
102
        '--no-commit', '--no-tag',
103
    ]
104
105 3
    current_version = attr.ib()
106 3
    version_files_to_replace = attr.ib(default=attr.Factory(list))
107
108 3
    def write_to_file(self, config_path: Path):
109 3
        bumpversion_cfg = textwrap.dedent(
110
            """\
111
            [bumpversion]
112
            current_version = {current_version}
113
114
            """
115
        ).format(**attr.asdict(self))
116
117 3
        bumpversion_files = '\n\n'.join([
118
            '[bumpversion:file:{}]'.format(file_name)
119
            for file_name in self.version_files_to_replace
120
        ])
121
122 3
        config_path.write_text(
123
            bumpversion_cfg + bumpversion_files
124
        )
125
126 3
def load_project_settings():
127 3
    changes_project_config_path = Path(PROJECT_CONFIG_FILE)
128
129 3
    project_settings = None
130 3
    if changes_project_config_path.exists():
131
        project_settings = Project(
132
            **(toml.load(changes_project_config_path.open())['changes'])
133
        )
134
135 3
    if not project_settings:
136 3
        project_settings = Project(
137
            releases_directory=str(Path(click.prompt(
138
                'Enter the directory to store your releases notes',
139
                DEFAULT_RELEASES_DIRECTORY,
140
                type=click.Path(exists=True, dir_okay=True)
141
            )))
142
        )
143
        # write config file
144 3
        changes_project_config_path.write_text(
0 ignored issues
show
Bug introduced by
The Instance of Path does not seem to have a member named write_text.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
145
            toml.dumps({
146
                'changes': attr.asdict(project_settings)
147
            })
148
        )
149
150
    # Initialise environment
151 3
    info('Indexing repository')
152 3
    project_settings.repository = GitRepository(
153
        auth_token=changes.settings.auth_token
154
    )
155
156
    # TODO: look in other locations / extract from bumpversion
157 3
    bumpversion = None
158 3
    bumpversion_config_path = Path('.bumpversion.cfg')
159 3
    if not bumpversion_config_path.exists():
160
        # list of file paths
161 3
        ask_user_for_version_files = []
162
163 3
        done = False
164 3
        while not done:
165 3
            version_file_path = Path(click.prompt(
166
                'Enter a path to a file that contains a version number',
167
                type=click.Path(
168
                    exists=True,
169
                    dir_okay=True,
170
                    file_okay=True,
171
                    readable=True
172
                )
173
            ))
174
175 3
            if version_file_path == Path('.'):
176 3
                done = True
177
            else:
178 3
                ask_user_for_version_files.append(version_file_path)
179
180 3
        bumpversion = BumpVersion(
181
            current_version=project_settings.repository.latest_version,
182
            version_files_to_replace=ask_user_for_version_files,
183
        )
184 3
        bumpversion.write_to_file(bumpversion_config_path)
185
186 3
    project_settings.bumpversion = bumpversion
187
188 3
    return project_settings
189
190
191 3
DEFAULTS = {
192
    'changelog': 'CHANGELOG.md',
193
    'readme': 'README.md',
194
    'github_auth_token': None,
195
}
196
197
198 3
class Config:
199 3
    test_command = None
200 3
    pypi = None
201 3
    skip_changelog = None
202 3
    changelog_content = None
203 3
    repo = None
204
205 3
    def __init__(self, module_name, dry_run, debug, no_input, requirements,
206
                 new_version, current_version, repo_url, version_prefix):
207 3
        self.module_name = module_name
208
        # module_name => project_name => curdir
209 3
        self.dry_run = dry_run
210 3
        self.debug = debug
211 3
        self.no_input = no_input
212 3
        self.requirements = requirements
213 3
        self.new_version = (
214
            version_prefix + new_version
215
            if version_prefix
216
            else new_version
217
        )
218 3
        self.current_version = current_version
219
220
221 3
def project_config():
222
    """Deprecated"""
223
    project_name = curdir
224
225
    config_path = Path(join(project_name, PROJECT_CONFIG_FILE))
226
227
    if not exists(config_path):
228
        store_settings(DEFAULTS.copy())
229
        return DEFAULTS
230
231
    return toml.load(io.open(config_path)) or {}
232
233
234 3
def store_settings(settings):
235
    pass
236
237