Completed
Push — stage ( 901070...369057 )
by Michael
09:53
created

load_project_settings()   B

Complexity

Conditions 6

Size

Total Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
c 2
b 0
f 0
dl 0
loc 63
ccs 0
cts 0
cp 0
crap 42
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
import io
4 3
import os
5 3
import sys
6 3
7
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 3
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
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 3
13 3
import changes
14
from changes.models import GitRepository
15
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
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
PROJECT_CONFIG_FILE = '.changes.toml'
29 3
DEFAULT_RELEASES_DIRECTORY = 'docs/releases'
30 3
31 3
32 3
@attr.s
33 3
class Changes(object):
34 3
    auth_token = attr.ib()
35
36 3
37
def load_settings():
38 3
    tool_config_path = Path(str(os.environ.get(
39
        'CHANGES_CONFIG_FILE',
40 3
        expanduser('~/.changes') if not IS_WINDOWS else
41 3
        expandvars(r'%APPDATA%\\.changes')
42 3
    )))
43 3
44 3
    tool_settings = None
45
    if tool_config_path.exists():
46
        tool_settings = Changes(
47
            **(toml.load(tool_config_path.open())['changes'])
48
        )
49 3
50
    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
        if auth_token:
54 3
            info('Found Github Auth Token in the environment')
55
56 3
        while not auth_token:
57
            info('No auth token found, asking for it')
58 3
            # 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
            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
        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 3
            toml.dumps({
70 3
                'changes': attr.asdict(tool_settings)
71
            })
72 3
        )
73 3
74
    return tool_settings
75
76
77
@attr.s
78
class Project(object):
79
    releases_directory = attr.ib()
80
    repository = attr.ib(default=None)
81
    bumpversion = attr.ib(default=None)
82
    towncrier = attr.ib(default=None)
83
84
    @property
85
    def bumpversion_configured(self):
86
        return isinstance(self.bumpversion, BumpVersion)
87
88
    @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
@attr.s
94
class BumpVersion(object):
95
    DRAFT_OPTIONS = [
96
        '--dry-run', '--verbose',
97
        '--no-commit', '--no-tag',
98
        '--allow-dirty',
99
    ]
100
    STAGE_OPTIONS = [
101
        '--verbose',
102
        '--no-commit', '--no-tag',
103
    ]
104
105
    current_version = attr.ib()
106
    version_files_to_replace = attr.ib(default=attr.Factory(list))
107
108
    def write_to_file(self, config_path: Path):
109
        bumpversion_cfg = textwrap.dedent(
110
            """\
111
            [bumpversion]
112
            current_version = {current_version}
113
114
            """
115
        ).format(**attr.asdict(self))
116
117
        bumpversion_files = '\n\n'.join([
118
            '[bumpversion:file:{}]'.format(file_name)
119
            for file_name in self.version_files_to_replace
120
        ])
121
122
        config_path.write_text(
123
            bumpversion_cfg + bumpversion_files
124
        )
125
126
def load_project_settings():
127
    changes_project_config_path = Path(PROJECT_CONFIG_FILE)
128
129
    project_settings = None
130
    if changes_project_config_path.exists():
131
        project_settings = Project(
132
            **(toml.load(changes_project_config_path.open())['changes'])
133
        )
134
135
    if not project_settings:
136
        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
        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
    info('Indexing repository')
152
    project_settings.repository = GitRepository(
153
        auth_token=changes.settings.auth_token
154
    )
155
156
    # TODO: look in other locations / extract from bumpversion
157
    bumpversion = None
158
    bumpversion_config_path = Path('.bumpversion.cfg')
159
    if not bumpversion_config_path.exists():
160
        # list of file paths
161
        ask_user_for_version_files = []
162
163
        done = False
164
        while not done:
165
            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
            if version_file_path == Path('.'):
176
                done = True
177
            else:
178
                ask_user_for_version_files.append(version_file_path)
179
180
        bumpversion = BumpVersion(
181
            current_version=project_settings.repository.latest_version,
182
            version_files_to_replace=ask_user_for_version_files,
183
        )
184
        bumpversion.write_to_file(bumpversion_config_path)
185
186
    project_settings.bumpversion = bumpversion
187
188
    return project_settings
189
190
191
DEFAULTS = {
192
    'changelog': 'CHANGELOG.md',
193
    'readme': 'README.md',
194
    'github_auth_token': None,
195
}
196
197
198
class Config:
199
    test_command = None
200
    pypi = None
201
    skip_changelog = None
202
    changelog_content = None
203
    repo = None
204
205
    def __init__(self, module_name, dry_run, debug, no_input, requirements,
206
                 new_version, current_version, repo_url, version_prefix):
207
        self.module_name = module_name
208
        # module_name => project_name => curdir
209
        self.dry_run = dry_run
210
        self.debug = debug
211
        self.no_input = no_input
212
        self.requirements = requirements
213
        self.new_version = (
214
            version_prefix + new_version
215
            if version_prefix
216
            else new_version
217
        )
218
        self.current_version = current_version
219
220
221
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
def store_settings(settings):
235
    pass
236
237