1 | """Update project metrics on The Coverage Space. |
||
2 | |||
3 | Usage: |
||
4 | coverage.space <owner/repo> <metric> [<value>] [--verbose] [--exit-code] |
||
5 | coverage.space (-h | --help) |
||
6 | coverage.space (-V | --version) |
||
7 | |||
8 | Options: |
||
9 | -h --help Show this help screen. |
||
10 | -V --version Show the program version. |
||
11 | -v --verbose Always display the coverage metrics. |
||
12 | -x --exit-code Return non-zero exit code on failures. |
||
13 | |||
14 | """ |
||
15 | |||
16 | 1 | from __future__ import unicode_literals |
|
17 | |||
18 | 1 | import sys |
|
19 | 1 | import time |
|
20 | 1 | import json |
|
21 | 1 | import logging |
|
22 | |||
23 | 1 | import six |
|
24 | 1 | from docopt import docopt |
|
25 | 1 | import requests |
|
26 | 1 | import colorama |
|
27 | 1 | from backports.shutil_get_terminal_size import get_terminal_size |
|
28 | |||
29 | 1 | from . import API, VERSION |
|
30 | |||
31 | 1 | from .plugins import get_coverage |
|
32 | 1 | from .cache import Cache |
|
33 | |||
34 | |||
35 | 1 | log = logging.getLogger(__name__) |
|
36 | 1 | cache = Cache() |
|
37 | |||
38 | |||
39 | 1 | def main(): |
|
40 | """Run the program.""" |
||
41 | 1 | colorama.init(autoreset=True) |
|
42 | 1 | arguments = docopt(__doc__, version=VERSION) |
|
43 | |||
44 | 1 | slug = arguments['<owner/repo>'] |
|
45 | 1 | metric = arguments['<metric>'] |
|
46 | 1 | value = arguments['<value>'] or get_coverage() |
|
47 | 1 | verbose = arguments['--verbose'] |
|
48 | 1 | hardfail = arguments['--exit-code'] |
|
49 | |||
50 | 1 | if verbose: |
|
51 | 1 | logging.basicConfig( |
|
52 | level=logging.DEBUG, |
||
53 | format="%(levelname)s: %(name)s: %(message)s", |
||
54 | ) |
||
55 | |||
56 | 1 | success = call(slug, metric, value, verbose, hardfail) |
|
57 | |||
58 | 1 | if not success and hardfail: |
|
59 | 1 | sys.exit(1) |
|
60 | |||
61 | |||
62 | 1 | def call(slug, metric, value, verbose=False, hardfail=False): |
|
63 | """Call the API and display errors.""" |
||
64 | 1 | url = "{}/{}".format(API, slug) |
|
65 | 1 | data = {metric: value} |
|
66 | 1 | response = request(url, data) |
|
67 | |||
68 | 1 | if response.status_code == 200: |
|
69 | 1 | if verbose: |
|
70 | 1 | display("coverage increased", response.json(), colorama.Fore.GREEN) |
|
71 | 1 | return True |
|
72 | |||
73 | 1 | elif response.status_code == 422: |
|
74 | 1 | color = colorama.Fore.RED if hardfail else colorama.Fore.YELLOW |
|
75 | 1 | display("coverage decreased", response.json(), color) |
|
76 | 1 | return False |
|
77 | |||
78 | else: |
||
79 | 1 | try: |
|
80 | 1 | data = response.json() |
|
81 | 1 | display("coverage unknown", data, colorama.Fore.RED) |
|
0 ignored issues
–
show
|
|||
82 | 1 | except (TypeError, ValueError) as exc: |
|
83 | 1 | data = response.data.decode('utf-8') |
|
84 | 1 | log.error("%s\n\nwhen decoding response:\n\n%s\n", exc, data) |
|
85 | 1 | return False |
|
86 | |||
87 | |||
88 | 1 | def request(url, data): |
|
89 | """Make request to external API.""" |
||
90 | 1 | log.info("Updating %s: %s", url, data) |
|
91 | |||
92 | 1 | response = cache.get(url, data) |
|
93 | 1 | if response is None: |
|
94 | 1 | for _ in range(3): |
|
95 | 1 | response = requests.put(url, data=data) |
|
96 | 1 | if response.status_code == 500: |
|
97 | 1 | time.sleep(3) |
|
98 | 1 | continue |
|
99 | else: |
||
100 | 1 | break |
|
101 | 1 | cache.set(url, data, response) |
|
102 | |||
103 | 1 | log.info("Response: %s", response) |
|
104 | |||
105 | 1 | return response |
|
106 | |||
107 | |||
108 | 1 | def display(title, data, color=""): |
|
109 | """Write colored text to the console.""" |
||
110 | 1 | color += colorama.Style.BRIGHT |
|
111 | 1 | width, _ = get_terminal_size() |
|
112 | 1 | six.print_(color + "{0:=^{1}}".format(' ' + title + ' ', width)) |
|
113 | 1 | six.print_(color + json.dumps(data, indent=4)) |
|
114 | six.print_(color + '=' * width) |
||
115 |
This check looks for calls to members that are non-existent. These calls will fail.
The member could have been renamed or removed.