kiba-build 0.1.11.dev1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kiba_build-0.1.11.dev1/PKG-INFO +17 -0
- kiba_build-0.1.11.dev1/README.md +1 -0
- kiba_build-0.1.11.dev1/buildpy/__init__.py +0 -0
- kiba_build-0.1.11.dev1/buildpy/lint_check.py +61 -0
- kiba_build-0.1.11.dev1/buildpy/py.typed +1 -0
- kiba_build-0.1.11.dev1/buildpy/security_check.py +156 -0
- kiba_build-0.1.11.dev1/buildpy/type_check.py +67 -0
- kiba_build-0.1.11.dev1/buildpy/util.py +83 -0
- kiba_build-0.1.11.dev1/buildpy/version.py +29 -0
- kiba_build-0.1.11.dev1/kiba_build.egg-info/PKG-INFO +17 -0
- kiba_build-0.1.11.dev1/kiba_build.egg-info/SOURCES.txt +15 -0
- kiba_build-0.1.11.dev1/kiba_build.egg-info/dependency_links.txt +1 -0
- kiba_build-0.1.11.dev1/kiba_build.egg-info/entry_points.txt +5 -0
- kiba_build-0.1.11.dev1/kiba_build.egg-info/requires.txt +9 -0
- kiba_build-0.1.11.dev1/kiba_build.egg-info/top_level.txt +1 -0
- kiba_build-0.1.11.dev1/pyproject.toml +26 -0
- kiba_build-0.1.11.dev1/setup.cfg +4 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: kiba-build
|
|
3
|
+
Version: 0.1.11.dev1
|
|
4
|
+
Summary: Kiba Labs' python building and testing utilities
|
|
5
|
+
Requires-Python: ~=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: asyncclick~=8.1.8
|
|
8
|
+
Requires-Dist: bandit~=1.8.3
|
|
9
|
+
Requires-Dist: bump-my-version>=0.29.0
|
|
10
|
+
Requires-Dist: click~=8.1.7
|
|
11
|
+
Requires-Dist: mypy~=1.15.0
|
|
12
|
+
Requires-Dist: pylint~=3.3.4
|
|
13
|
+
Requires-Dist: simple-chalk~=0.1.0
|
|
14
|
+
Requires-Dist: twine~=6.1.0
|
|
15
|
+
Requires-Dist: wheel~=0.45.1
|
|
16
|
+
|
|
17
|
+
# Build-Py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Build-Py
|
|
File without changes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
from pylint.lint import Run as run_pylint
|
|
6
|
+
from pylint.reporters import CollectingReporter
|
|
7
|
+
|
|
8
|
+
from buildpy.util import GitHubAnnotationsReporter
|
|
9
|
+
from buildpy.util import Message
|
|
10
|
+
from buildpy.util import MessageParser
|
|
11
|
+
from buildpy.util import PrettyReporter
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PylintMessageParser(CollectingReporter, MessageParser):
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def _get_error_level(pylintLevel: str) -> str:
|
|
18
|
+
pylintLevel = pylintLevel.lower()
|
|
19
|
+
if pylintLevel == 'info':
|
|
20
|
+
return 'notice'
|
|
21
|
+
if pylintLevel == 'warning':
|
|
22
|
+
return 'warning'
|
|
23
|
+
return 'error'
|
|
24
|
+
|
|
25
|
+
def parse_messages(self, rawMessages: List[str]) -> List[Message]:
|
|
26
|
+
raise NotImplementedError
|
|
27
|
+
|
|
28
|
+
def get_messages(self) -> List[Message]:
|
|
29
|
+
output: List[Message] = []
|
|
30
|
+
for rawMessage in self.messages:
|
|
31
|
+
output.append(Message(
|
|
32
|
+
path=os.path.relpath(rawMessage.abspath),
|
|
33
|
+
line=rawMessage.line,
|
|
34
|
+
column=rawMessage.column + 1,
|
|
35
|
+
code=rawMessage.symbol,
|
|
36
|
+
text=rawMessage.msg.strip() or '',
|
|
37
|
+
level=self._get_error_level(pylintLevel=rawMessage.category),
|
|
38
|
+
))
|
|
39
|
+
return output
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@click.command()
|
|
43
|
+
@click.argument('targets', nargs=-1)
|
|
44
|
+
@click.option('-o', '--output-file', 'outputFilename', required=False, type=str)
|
|
45
|
+
@click.option('-f', '--output-format', 'outputFormat', required=False, type=str, default='pretty')
|
|
46
|
+
@click.option('-c', '--config-file-path', 'configFilePath', required=False, type=str)
|
|
47
|
+
def run(targets: List[str], outputFilename: str, outputFormat: str, configFilePath: str) -> None:
|
|
48
|
+
currentDirectory = os.path.dirname(os.path.realpath(__file__))
|
|
49
|
+
pylintConfigFilePath = configFilePath or f'{currentDirectory}/pyproject.toml'
|
|
50
|
+
pylintMessageParser = PylintMessageParser()
|
|
51
|
+
run_pylint([f'--rcfile={pylintConfigFilePath}', f'--jobs=0'] + list(targets), reporter=pylintMessageParser, exit=False)
|
|
52
|
+
reporter = GitHubAnnotationsReporter() if outputFormat == 'annotations' else PrettyReporter()
|
|
53
|
+
output = reporter.create_output(messages=pylintMessageParser.get_messages())
|
|
54
|
+
if outputFilename:
|
|
55
|
+
with open(outputFilename, 'w') as outputFile:
|
|
56
|
+
outputFile.write(output)
|
|
57
|
+
else:
|
|
58
|
+
print(output)
|
|
59
|
+
|
|
60
|
+
if __name__ == '__main__':
|
|
61
|
+
run() # pylint: disable=no-value-for-parameter
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Marker file for PEP 561 (https://www.python.org/dev/peps/pep-0561/). This package uses inline types.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from buildpy.util import GitHubAnnotationsReporter
|
|
8
|
+
from buildpy.util import Message
|
|
9
|
+
from buildpy.util import MessageParser
|
|
10
|
+
from buildpy.util import PrettyReporter
|
|
11
|
+
|
|
12
|
+
# TODO(krishan711): remove this once test_name is enabled https://github.com/PyCQA/bandit/issues/962
|
|
13
|
+
BANDIT_CODES = {
|
|
14
|
+
'B101': 'assert_used',
|
|
15
|
+
'B102': 'exec_used',
|
|
16
|
+
'B103': 'set_bad_file_permissions',
|
|
17
|
+
'B104': 'hardcoded_bind_all_interfaces',
|
|
18
|
+
'B105': 'hardcoded_password_string',
|
|
19
|
+
'B106': 'hardcoded_password_funcarg',
|
|
20
|
+
'B107': 'hardcoded_password_default',
|
|
21
|
+
'B108': 'hardcoded_tmp_directory',
|
|
22
|
+
'B110': 'try_except_pass',
|
|
23
|
+
'B112': 'try_except_continue',
|
|
24
|
+
'B201': 'flask_debug_true',
|
|
25
|
+
'B301': 'pickle',
|
|
26
|
+
'B302': 'marshal',
|
|
27
|
+
'B303': 'md5',
|
|
28
|
+
'B304': 'ciphers',
|
|
29
|
+
'B305': 'cipher_modes',
|
|
30
|
+
'B306': 'mktemp_q',
|
|
31
|
+
'B307': 'eval',
|
|
32
|
+
'B308': 'mark_safe',
|
|
33
|
+
'B309': 'httpsconnection',
|
|
34
|
+
'B310': 'urllib_urlopen',
|
|
35
|
+
'B311': 'random',
|
|
36
|
+
'B312': 'telnetlib',
|
|
37
|
+
'B313': 'xml_bad_cElementTree',
|
|
38
|
+
'B314': 'xml_bad_ElementTree',
|
|
39
|
+
'B315': 'xml_bad_expatreader',
|
|
40
|
+
'B316': 'xml_bad_expatbuilder',
|
|
41
|
+
'B317': 'xml_bad_sax',
|
|
42
|
+
'B318': 'xml_bad_minidom',
|
|
43
|
+
'B319': 'xml_bad_pulldom',
|
|
44
|
+
'B320': 'xml_bad_etree',
|
|
45
|
+
'B321': 'ftplib',
|
|
46
|
+
'B323': 'unverified_context',
|
|
47
|
+
'B324': 'hashlib_insecure_functions',
|
|
48
|
+
'B325': 'tempnam',
|
|
49
|
+
'B401': 'import_telnetlib',
|
|
50
|
+
'B402': 'import_ftplib',
|
|
51
|
+
'B403': 'import_pickle',
|
|
52
|
+
'B404': 'import_subprocess',
|
|
53
|
+
'B405': 'import_xml_etree',
|
|
54
|
+
'B406': 'import_xml_sax',
|
|
55
|
+
'B407': 'import_xml_expat',
|
|
56
|
+
'B408': 'import_xml_minidom',
|
|
57
|
+
'B409': 'import_xml_pulldom',
|
|
58
|
+
'B410': 'import_lxml',
|
|
59
|
+
'B411': 'import_xmlrpclib',
|
|
60
|
+
'B412': 'import_httpoxy',
|
|
61
|
+
'B413': 'import_pycrypto',
|
|
62
|
+
'B415': 'import_pyghmi',
|
|
63
|
+
'B501': 'request_with_no_cert_validation',
|
|
64
|
+
'B502': 'ssl_with_bad_version',
|
|
65
|
+
'B503': 'ssl_with_bad_defaults',
|
|
66
|
+
'B504': 'ssl_with_no_version',
|
|
67
|
+
'B505': 'weak_cryptographic_key',
|
|
68
|
+
'B506': 'yaml_load',
|
|
69
|
+
'B507': 'ssh_no_host_key_verification',
|
|
70
|
+
'B508': 'snmp_insecure_version',
|
|
71
|
+
'B509': 'snmp_weak_cryptography',
|
|
72
|
+
'B601': 'paramiko_calls',
|
|
73
|
+
'B602': 'subprocess_popen_with_shell_equals_true',
|
|
74
|
+
'B603': 'subprocess_without_shell_equals_true',
|
|
75
|
+
'B604': 'any_other_function_with_shell_equals_true',
|
|
76
|
+
'B605': 'start_process_with_a_shell',
|
|
77
|
+
'B606': 'start_process_with_no_shell',
|
|
78
|
+
'B607': 'start_process_with_partial_path',
|
|
79
|
+
'B608': 'hardcoded_sql_expressions',
|
|
80
|
+
'B609': 'linux_commands_wildcard_injection',
|
|
81
|
+
'B610': 'django_extra_used',
|
|
82
|
+
'B611': 'django_rawsql_used',
|
|
83
|
+
'B701': 'jinja2_autoescape_false',
|
|
84
|
+
'B702': 'use_of_mako_templates',
|
|
85
|
+
'B703': 'django_mark_safe',
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
class BanditMessageParser(MessageParser):
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def _get_error_level(banditLevel: str) -> str:
|
|
92
|
+
banditLevel = banditLevel.lower()
|
|
93
|
+
if banditLevel == 'low':
|
|
94
|
+
return 'notice'
|
|
95
|
+
if banditLevel == 'warning':
|
|
96
|
+
return 'warning'
|
|
97
|
+
return 'error'
|
|
98
|
+
|
|
99
|
+
def parse_messages(self, rawMessages: List[str]) -> List[Message]:
|
|
100
|
+
output: List[Message] = []
|
|
101
|
+
for rawMessage in rawMessages:
|
|
102
|
+
rawMessage = rawMessage.strip()
|
|
103
|
+
if len(rawMessage) == 0 or rawMessage.startswith('filename,test_name,'):
|
|
104
|
+
continue
|
|
105
|
+
print(rawMessage)
|
|
106
|
+
rawMessageParts = rawMessage.split('\t')
|
|
107
|
+
if len(rawMessageParts) == 1:
|
|
108
|
+
continue
|
|
109
|
+
if rawMessageParts[0] == '[tester]':
|
|
110
|
+
output.append(Message(
|
|
111
|
+
path='',
|
|
112
|
+
line=0,
|
|
113
|
+
column=0,
|
|
114
|
+
code='tester',
|
|
115
|
+
text=rawMessageParts[2],
|
|
116
|
+
level=self._get_error_level(banditLevel=rawMessageParts[1]),
|
|
117
|
+
))
|
|
118
|
+
else:
|
|
119
|
+
output.append(Message(
|
|
120
|
+
path=rawMessageParts[0],
|
|
121
|
+
line=int(rawMessageParts[1]),
|
|
122
|
+
column=int(rawMessageParts[2]),
|
|
123
|
+
code=BANDIT_CODES[rawMessageParts[3]],
|
|
124
|
+
text=rawMessageParts[4],
|
|
125
|
+
level=self._get_error_level(banditLevel=rawMessageParts[5]),
|
|
126
|
+
))
|
|
127
|
+
return output
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@click.command()
|
|
131
|
+
@click.argument('targets', nargs=-1)
|
|
132
|
+
@click.option('-o', '--output-file', 'outputFilename', required=False, type=str)
|
|
133
|
+
@click.option('-f', '--output-format', 'outputFormat', required=False, type=str, default='pretty')
|
|
134
|
+
@click.option('-c', '--config-file-path', 'configFilePath', required=False, type=str)
|
|
135
|
+
def run(targets: List[str], outputFilename: str, outputFormat: str, configFilePath: str) -> None:
|
|
136
|
+
currentDirectory = os.path.dirname(os.path.realpath(__file__))
|
|
137
|
+
messages: List[str] = []
|
|
138
|
+
banditConfigFilePath = configFilePath or f'{currentDirectory}/pyproject.toml'
|
|
139
|
+
# TODO(krishan711): use test_name here once enabled https://github.com/PyCQA/bandit/issues/962
|
|
140
|
+
messageTemplate = '{abspath}\t{line}\t{col}\t{test_id}\t{msg}\t{severity}'
|
|
141
|
+
try:
|
|
142
|
+
subprocess.check_output(f'bandit --configfile {banditConfigFilePath} --silent --severity-level medium --confidence-level medium --format custom --msg-template \"{messageTemplate}\" --recursive {" ".join(targets)}', stderr=subprocess.STDOUT, shell=True) # nosec=subprocess_popen_with_shell_equals_true
|
|
143
|
+
except subprocess.CalledProcessError as exception:
|
|
144
|
+
messages = exception.output.decode().split('\n')
|
|
145
|
+
messageParser = BanditMessageParser()
|
|
146
|
+
parsedMessages = messageParser.parse_messages(rawMessages=messages)
|
|
147
|
+
reporter = GitHubAnnotationsReporter() if outputFormat == 'annotations' else PrettyReporter()
|
|
148
|
+
output = reporter.create_output(messages=parsedMessages)
|
|
149
|
+
if outputFilename:
|
|
150
|
+
with open(outputFilename, 'w') as outputFile:
|
|
151
|
+
outputFile.write(output)
|
|
152
|
+
else:
|
|
153
|
+
print(output)
|
|
154
|
+
|
|
155
|
+
if __name__ == '__main__':
|
|
156
|
+
run() # pylint: disable=no-value-for-parameter
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import subprocess
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from buildpy.util import GitHubAnnotationsReporter
|
|
9
|
+
from buildpy.util import Message
|
|
10
|
+
from buildpy.util import MessageParser
|
|
11
|
+
from buildpy.util import PrettyReporter
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MypyMessageParser(MessageParser):
|
|
15
|
+
|
|
16
|
+
def parse_messages(self, rawMessages: List[str]) -> List[Message]:
|
|
17
|
+
output: List[Message] = []
|
|
18
|
+
for rawMessage in rawMessages:
|
|
19
|
+
rawMessage = rawMessage.strip()
|
|
20
|
+
if len(rawMessage) == 0 \
|
|
21
|
+
or ' note: ' in rawMessage \
|
|
22
|
+
or 'Use "-> None" if function does not return a value' in rawMessage:
|
|
23
|
+
continue
|
|
24
|
+
if 'Error importing plugin "pydantic.mypy":' in rawMessage:
|
|
25
|
+
# NOTE(krishan711): we use pydantic rules but it may not be installed (like in this repo)
|
|
26
|
+
continue
|
|
27
|
+
match1 = re.match(r'(.*):(\d*):(\d*): (.*): (.*) \[(.*)\]', rawMessage)
|
|
28
|
+
match2 = None
|
|
29
|
+
if not match1:
|
|
30
|
+
# match2 = match1 without column number
|
|
31
|
+
match2 = re.match(r'(.*):(\d*): (.*): (.*) \[(.*)\]', rawMessage)
|
|
32
|
+
output.append(Message(
|
|
33
|
+
path=match1.group(1) if match1 else (match2.group(1) if match2 else ''),
|
|
34
|
+
line=int(match1.group(2)) if match1 else (int(match2.group(2)) if match2 else 0),
|
|
35
|
+
column=int(match1.group(3)) if match1 else (0 if match2 else 0),
|
|
36
|
+
code=match1.group(6) if match1 else (match2.group(5) if match2 else 'unparsed'),
|
|
37
|
+
text=match1.group(5).strip() if match1 else (match2.group(4).strip() if match2 else rawMessage.strip()),
|
|
38
|
+
level=match1.group(4) if match1 else (match2.group(3) if match2 else 'error'),
|
|
39
|
+
))
|
|
40
|
+
return output
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@click.command()
|
|
44
|
+
@click.argument('targets', nargs=-1)
|
|
45
|
+
@click.option('-o', '--output-file', 'outputFilename', required=False, type=str)
|
|
46
|
+
@click.option('-f', '--output-format', 'outputFormat', required=False, type=str, default='pretty')
|
|
47
|
+
@click.option('-c', '--config-file-path', 'configFilePath', required=False, type=str)
|
|
48
|
+
def run(targets: List[str], outputFilename: str, outputFormat: str, configFilePath: str) -> None:
|
|
49
|
+
currentDirectory = os.path.dirname(os.path.realpath(__file__))
|
|
50
|
+
mypyConfigFilePath = configFilePath or f'{currentDirectory}/pyproject.toml'
|
|
51
|
+
messages: List[str] = []
|
|
52
|
+
try:
|
|
53
|
+
subprocess.check_output(f'mypy {" ".join(targets)} --config-file {mypyConfigFilePath} --no-color-output --hide-error-context --no-pretty --no-error-summary --show-error-codes --show-column-numbers', stderr=subprocess.STDOUT, shell=True) # nosec=subprocess_popen_with_shell_equals_true
|
|
54
|
+
except subprocess.CalledProcessError as exception:
|
|
55
|
+
messages = exception.output.decode().split('\n')
|
|
56
|
+
messageParser = MypyMessageParser()
|
|
57
|
+
parsedMessages = messageParser.parse_messages(rawMessages=messages)
|
|
58
|
+
reporter = GitHubAnnotationsReporter() if outputFormat == 'annotations' else PrettyReporter()
|
|
59
|
+
output = reporter.create_output(messages=parsedMessages)
|
|
60
|
+
if outputFilename:
|
|
61
|
+
with open(outputFilename, 'w') as outputFile:
|
|
62
|
+
outputFile.write(output)
|
|
63
|
+
else:
|
|
64
|
+
print(output)
|
|
65
|
+
|
|
66
|
+
if __name__ == '__main__':
|
|
67
|
+
run() # pylint: disable=no-value-for-parameter
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
from simple_chalk import chalk # type: ignore
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclasses.dataclass
|
|
11
|
+
class Message:
|
|
12
|
+
path: str
|
|
13
|
+
line: int
|
|
14
|
+
column: int
|
|
15
|
+
code: str
|
|
16
|
+
text: str
|
|
17
|
+
level: str # (error, warning, notice)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MessageParser:
|
|
21
|
+
|
|
22
|
+
def parse_messages(self, rawMessages: List[str]) -> List[Message]:
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class KibaReporter:
|
|
27
|
+
|
|
28
|
+
def create_output(self, messages: List[Message]) -> str:
|
|
29
|
+
raise NotImplementedError
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class GitHubAnnotationsReporter(KibaReporter):
|
|
33
|
+
|
|
34
|
+
def create_output(self, messages: List[Message]) -> str:
|
|
35
|
+
annotations = []
|
|
36
|
+
for message in messages:
|
|
37
|
+
annotation = {
|
|
38
|
+
'path': os.path.relpath(message.path) if message.path else '<unknown>',
|
|
39
|
+
'start_line': message.line,
|
|
40
|
+
'end_line': message.line,
|
|
41
|
+
'start_column': message.column,
|
|
42
|
+
'end_column': message.column,
|
|
43
|
+
'message': f'[{message.code}] {message.text}',
|
|
44
|
+
'annotation_level': 'notice' if message.level == 'notice' else ('warning' if message.level == 'warning' else 'failure'),
|
|
45
|
+
}
|
|
46
|
+
annotations.append(annotation)
|
|
47
|
+
return json.dumps(annotations)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class PrettyReporter(KibaReporter):
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def get_summary(errorCount: int, warningCount: int) -> str:
|
|
54
|
+
summary = ''
|
|
55
|
+
if errorCount:
|
|
56
|
+
summary += chalk.red(f'{errorCount} errors')
|
|
57
|
+
if warningCount:
|
|
58
|
+
summary = f'{summary} and ' if summary else ''
|
|
59
|
+
summary += chalk.yellow(f'{warningCount} warnings')
|
|
60
|
+
return summary
|
|
61
|
+
|
|
62
|
+
def create_output(self, messages: List[Message]) -> str:
|
|
63
|
+
fileMessageMap = defaultdict(list)
|
|
64
|
+
for message in messages:
|
|
65
|
+
fileMessageMap[os.path.relpath(message.path) if message.path else '<unknown>'].append(message)
|
|
66
|
+
totalErrorCount = 0
|
|
67
|
+
totalWarningCount = 0
|
|
68
|
+
outputs = []
|
|
69
|
+
for (filePath, fileMessages) in fileMessageMap.items():
|
|
70
|
+
fileOutputs = []
|
|
71
|
+
for message in fileMessages:
|
|
72
|
+
location = chalk.grey(f'{filePath}:{message.line}:{message.column}')
|
|
73
|
+
color = chalk.white if message.level == 'notice' else (chalk.yellow if message.level == 'warning' else chalk.red)
|
|
74
|
+
fileOutputs.append(f'{location} [{color(message.code)}] {message.text}')
|
|
75
|
+
errorCount = sum(1 for message in fileMessages if message.level == 'error')
|
|
76
|
+
totalErrorCount += errorCount
|
|
77
|
+
warningCount = sum(1 for message in fileMessages if message.level == 'warning')
|
|
78
|
+
totalWarningCount += warningCount
|
|
79
|
+
fileOutputString = '\n'.join(fileOutputs)
|
|
80
|
+
outputs.append(f'{self.get_summary(errorCount, warningCount)} in {filePath}\n{fileOutputString}\n')
|
|
81
|
+
output = '\n'.join(outputs)
|
|
82
|
+
output += f'\nFailed due to {self.get_summary(totalErrorCount, totalWarningCount)}.' if (totalErrorCount or totalWarningCount) else chalk.green('Passed.')
|
|
83
|
+
return output
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import importlib.metadata
|
|
2
|
+
import subprocess
|
|
3
|
+
import tomllib
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def generate_command(part: str) -> str:
|
|
9
|
+
with open('pyproject.toml', 'r') as file:
|
|
10
|
+
pyproject = tomllib.loads(file.read())
|
|
11
|
+
currentVersion = pyproject['project']['version']
|
|
12
|
+
return f"bump-my-version bump --allow-dirty --current-version \"{currentVersion}\" --parse '(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\.dev(?P<dev>\\d+))?' --serialize '{{major}}.{{minor}}.{{patch}}.dev{{dev}}' --serialize '{{major}}.{{minor}}.{{patch}}' {part} pyproject.toml"
|
|
13
|
+
|
|
14
|
+
@click.command()
|
|
15
|
+
@click.option('-p', '--part', 'part', required=True, type=str)
|
|
16
|
+
@click.option('-c', '--count', 'count', required=False, type=int, default=1)
|
|
17
|
+
def run(part: str, count: int) -> None:
|
|
18
|
+
print('here', part, count)
|
|
19
|
+
if count == 0:
|
|
20
|
+
print('No version bump required')
|
|
21
|
+
return
|
|
22
|
+
# NOTE(krishan711): for dev releases bump the patch first
|
|
23
|
+
if part == 'dev':
|
|
24
|
+
subprocess.check_output(generate_command(part='patch'), stderr=subprocess.STDOUT, shell=True) # nosec=subprocess_popen_with_shell_equals_true
|
|
25
|
+
for _ in range(count):
|
|
26
|
+
subprocess.check_output(generate_command(part=part), stderr=subprocess.STDOUT, shell=True) # nosec=subprocess_popen_with_shell_equals_true
|
|
27
|
+
|
|
28
|
+
if __name__ == '__main__':
|
|
29
|
+
run() # pylint: disable=no-value-for-parameter
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: kiba-build
|
|
3
|
+
Version: 0.1.11.dev1
|
|
4
|
+
Summary: Kiba Labs' python building and testing utilities
|
|
5
|
+
Requires-Python: ~=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: asyncclick~=8.1.8
|
|
8
|
+
Requires-Dist: bandit~=1.8.3
|
|
9
|
+
Requires-Dist: bump-my-version>=0.29.0
|
|
10
|
+
Requires-Dist: click~=8.1.7
|
|
11
|
+
Requires-Dist: mypy~=1.15.0
|
|
12
|
+
Requires-Dist: pylint~=3.3.4
|
|
13
|
+
Requires-Dist: simple-chalk~=0.1.0
|
|
14
|
+
Requires-Dist: twine~=6.1.0
|
|
15
|
+
Requires-Dist: wheel~=0.45.1
|
|
16
|
+
|
|
17
|
+
# Build-Py
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
buildpy/__init__.py
|
|
4
|
+
buildpy/lint_check.py
|
|
5
|
+
buildpy/py.typed
|
|
6
|
+
buildpy/security_check.py
|
|
7
|
+
buildpy/type_check.py
|
|
8
|
+
buildpy/util.py
|
|
9
|
+
buildpy/version.py
|
|
10
|
+
kiba_build.egg-info/PKG-INFO
|
|
11
|
+
kiba_build.egg-info/SOURCES.txt
|
|
12
|
+
kiba_build.egg-info/dependency_links.txt
|
|
13
|
+
kiba_build.egg-info/entry_points.txt
|
|
14
|
+
kiba_build.egg-info/requires.txt
|
|
15
|
+
kiba_build.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
buildpy
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "kiba-build"
|
|
3
|
+
version = "0.1.11.dev1"
|
|
4
|
+
description = "Kiba Labs' python building and testing utilities"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = "~=3.11"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"asyncclick~=8.1.8",
|
|
9
|
+
"bandit~=1.8.3",
|
|
10
|
+
"bump-my-version>=0.29.0",
|
|
11
|
+
"click~=8.1.7",
|
|
12
|
+
"mypy~=1.15.0",
|
|
13
|
+
"pylint~=3.3.4",
|
|
14
|
+
"simple-chalk~=0.1.0",
|
|
15
|
+
"twine~=6.1.0",
|
|
16
|
+
"wheel~=0.45.1",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
lint-check = "buildpy.lint_check:run"
|
|
21
|
+
type-check = "buildpy.type_check:run"
|
|
22
|
+
security-check = "buildpy.security_check:run"
|
|
23
|
+
version = "buildpy.version:run"
|
|
24
|
+
|
|
25
|
+
[tool.uv]
|
|
26
|
+
package = true
|