squad 1.89__py3-none-any.whl → 1.90__py3-none-any.whl
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.
Potentially problematic release.
This version of squad might be problematic. Click here for more details.
- squad/api/views.py +1 -1
- squad/core/management/commands/import_data.py +2 -1
- squad/core/models.py +2 -2
- squad/core/tasks/__init__.py +3 -3
- squad/core/utils.py +7 -4
- squad/plugins/lib/__init__.py +1 -0
- squad/plugins/lib/base_log_parser.py +152 -0
- squad/plugins/linux_log_parser.py +5 -120
- squad/settings.py +15 -11
- squad/version.py +1 -1
- {squad-1.89.dist-info → squad-1.90.dist-info}/METADATA +13 -12
- {squad-1.89.dist-info → squad-1.90.dist-info}/RECORD +16 -14
- {squad-1.89.dist-info → squad-1.90.dist-info}/WHEEL +1 -1
- {squad-1.89.dist-info → squad-1.90.dist-info}/entry_points.txt +1 -0
- {squad-1.89.dist-info → squad-1.90.dist-info}/COPYING +0 -0
- {squad-1.89.dist-info → squad-1.90.dist-info}/top_level.txt +0 -0
squad/api/views.py
CHANGED
@@ -105,7 +105,7 @@ def add_test_run(request, group_slug, project_slug, version, environment_slug):
|
|
105
105
|
if 'attachment' in request.FILES:
|
106
106
|
attachments = {}
|
107
107
|
for f in request.FILES.getlist('attachment'):
|
108
|
-
attachments[f.name] =
|
108
|
+
attachments[f.name] = f
|
109
109
|
test_run_data['attachments'] = attachments
|
110
110
|
|
111
111
|
receive = ReceiveTestRun(project)
|
@@ -2,6 +2,7 @@ from glob import glob
|
|
2
2
|
import os
|
3
3
|
import re
|
4
4
|
from django.core.management.base import BaseCommand
|
5
|
+
from django.core.files import File
|
5
6
|
|
6
7
|
|
7
8
|
from squad.core.models import Build
|
@@ -123,7 +124,7 @@ class Command(BaseCommand):
|
|
123
124
|
for f in glob(os.path.join(directory, '*')):
|
124
125
|
name = os.path.basename(f)
|
125
126
|
if name not in ['metrics.json', 'metadata.json', 'tests.json']:
|
126
|
-
attachments[name] = open(f, 'rb')
|
127
|
+
attachments[name] = File(open(f, 'rb'))
|
127
128
|
|
128
129
|
if not self.options['silent']:
|
129
130
|
print("Importing test run: %s" % directory)
|
squad/core/models.py
CHANGED
@@ -909,8 +909,8 @@ class Attachment(models.Model):
|
|
909
909
|
self.__data__ = b''
|
910
910
|
return self.__data__
|
911
911
|
|
912
|
-
def save_file(self, filename,
|
913
|
-
storage_save(self, self.storage, filename,
|
912
|
+
def save_file(self, filename, file):
|
913
|
+
storage_save(self, self.storage, filename, file)
|
914
914
|
|
915
915
|
|
916
916
|
class SuiteMetadata(models.Model):
|
squad/core/tasks/__init__.py
CHANGED
@@ -172,9 +172,9 @@ class ReceiveTestRun(object):
|
|
172
172
|
if log_file is not None:
|
173
173
|
testrun.save_log_file(log_file)
|
174
174
|
|
175
|
-
for filename,
|
176
|
-
attachment = testrun.attachments.create(filename=filename, length=
|
177
|
-
attachment.save_file(filename,
|
175
|
+
for filename, file in attachments.items():
|
176
|
+
attachment = testrun.attachments.create(filename=filename, length=file.size)
|
177
|
+
attachment.save_file(filename, file)
|
178
178
|
|
179
179
|
testrun.refresh_from_db()
|
180
180
|
|
squad/core/utils.py
CHANGED
@@ -169,8 +169,11 @@ def log_deletion(request, object, message):
|
|
169
169
|
|
170
170
|
|
171
171
|
def storage_save(obj, storage_field, filename, content):
|
172
|
-
content_bytes = content or ''
|
173
|
-
if type(content_bytes) is str:
|
174
|
-
content_bytes = content_bytes.encode()
|
175
172
|
filename = '%s/%s/%s' % (obj.__class__.__name__.lower(), obj.pk, filename)
|
176
|
-
|
173
|
+
if type(content) in [bytes, str]:
|
174
|
+
content_bytes = content or ''
|
175
|
+
if type(content_bytes) is str:
|
176
|
+
content_bytes = content_bytes.encode()
|
177
|
+
storage_field.save(filename, ContentFile(content_bytes))
|
178
|
+
else:
|
179
|
+
storage_field.save(filename, content)
|
@@ -0,0 +1 @@
|
|
1
|
+
from squad.plugins import Plugin # noqa
|
@@ -0,0 +1,152 @@
|
|
1
|
+
import hashlib
|
2
|
+
import re
|
3
|
+
from collections import defaultdict
|
4
|
+
|
5
|
+
from django.template.defaultfilters import slugify
|
6
|
+
|
7
|
+
REGEX_NAME = 0
|
8
|
+
REGEX_BODY = 1
|
9
|
+
REGEX_EXTRACT_NAME = 2
|
10
|
+
|
11
|
+
|
12
|
+
class BaseLogParser:
|
13
|
+
def compile_regexes(self, regexes):
|
14
|
+
combined = [r"(%s)" % r[REGEX_BODY] for r in regexes]
|
15
|
+
return re.compile(r"|".join(combined), re.S | re.M)
|
16
|
+
|
17
|
+
def remove_numbers_and_time(self, snippet):
|
18
|
+
without_numbers = re.sub(r"(0x[a-f0-9]+|[<\[][0-9a-f]+?[>\]]|\d+)", "", snippet)
|
19
|
+
without_time = re.sub(r"^\[[^\]]+\]", "", without_numbers)
|
20
|
+
|
21
|
+
return without_time
|
22
|
+
|
23
|
+
def create_name(self, snippet, compiled_regex=None):
|
24
|
+
matches = None
|
25
|
+
if compiled_regex:
|
26
|
+
matches = compiled_regex.findall(snippet)
|
27
|
+
if not matches:
|
28
|
+
# Only extract a name if we provide a regex to extract the name and
|
29
|
+
# there is a match
|
30
|
+
return None
|
31
|
+
snippet = matches[0]
|
32
|
+
without_numbers_and_time = self.remove_numbers_and_time(snippet)
|
33
|
+
|
34
|
+
# Limit the name length to 191 characters, since the max name length
|
35
|
+
# for SuiteMetadata in SQUAD is 256 characters. The SHA and "-" take 65
|
36
|
+
# characters: 256-65=191
|
37
|
+
return slugify(without_numbers_and_time)[:191]
|
38
|
+
|
39
|
+
def create_shasum(self, snippet):
|
40
|
+
sha = hashlib.sha256()
|
41
|
+
without_numbers_and_time = self.remove_numbers_and_time(snippet)
|
42
|
+
sha.update(without_numbers_and_time.encode())
|
43
|
+
return sha.hexdigest()
|
44
|
+
|
45
|
+
def create_name_log_dict(self, test_name, lines, test_regex=None):
|
46
|
+
"""
|
47
|
+
Produce a dictionary with the test names as keys and the extracted logs
|
48
|
+
for that test name as values. There will be at least one test name per
|
49
|
+
regex. If there were any matches for a given regex, then a new test
|
50
|
+
will be generated using test_name + shasum.
|
51
|
+
"""
|
52
|
+
# Run the REGEX_EXTRACT_NAME regex over the log lines to sort them by
|
53
|
+
# extracted name. If no name is extracted or the log parser did not
|
54
|
+
# have any output for a particular regex, just use the default name
|
55
|
+
# (for example "check-kernel-oops").
|
56
|
+
tests_without_shas_to_create = defaultdict(set)
|
57
|
+
tests_with_shas_to_create = defaultdict(set)
|
58
|
+
|
59
|
+
# If there are no lines, use the default name and create a passing
|
60
|
+
# test. For example "check-kernel-oops"
|
61
|
+
if not lines:
|
62
|
+
tests_without_shas_to_create[test_name] = []
|
63
|
+
|
64
|
+
# If there are lines, then create the tests for these.
|
65
|
+
for line in lines:
|
66
|
+
extracted_name = self.create_name(line, test_regex)
|
67
|
+
if extracted_name:
|
68
|
+
extended_test_name = f"{test_name}-{extracted_name}"
|
69
|
+
else:
|
70
|
+
extended_test_name = test_name
|
71
|
+
tests_without_shas_to_create[extended_test_name].add(line)
|
72
|
+
|
73
|
+
for name, test_lines in tests_without_shas_to_create.items():
|
74
|
+
# Some lines of the matched regex might be the same, and we don't want to create
|
75
|
+
# multiple tests like test1-sha1, test1-sha1, etc, so we'll create a set of sha1sums
|
76
|
+
# then create only new tests for unique sha's
|
77
|
+
|
78
|
+
for line in test_lines:
|
79
|
+
sha = self.create_shasum(line)
|
80
|
+
name_with_sha = f"{name}-{sha}"
|
81
|
+
tests_with_shas_to_create[name_with_sha].add(line)
|
82
|
+
|
83
|
+
return tests_without_shas_to_create, tests_with_shas_to_create
|
84
|
+
|
85
|
+
def create_squad_tests_from_name_log_dict(
|
86
|
+
self, suite, testrun, tests_without_shas_to_create, tests_with_shas_to_create
|
87
|
+
):
|
88
|
+
# Import SuiteMetadata from SQUAD only when required so BaseLogParser
|
89
|
+
# does not require a SQUAD to work. This makes it easier to reuse this
|
90
|
+
# class outside of SQUAD for testing and developing log parser
|
91
|
+
# patterns.
|
92
|
+
from squad.core.models import SuiteMetadata
|
93
|
+
|
94
|
+
for name, lines in tests_without_shas_to_create.items():
|
95
|
+
metadata, _ = SuiteMetadata.objects.get_or_create(
|
96
|
+
suite=suite.slug, name=name, kind="test"
|
97
|
+
)
|
98
|
+
testrun.tests.create(
|
99
|
+
suite=suite,
|
100
|
+
result=(len(lines) == 0),
|
101
|
+
log="\n".join(lines),
|
102
|
+
metadata=metadata,
|
103
|
+
build=testrun.build,
|
104
|
+
environment=testrun.environment,
|
105
|
+
)
|
106
|
+
for name_with_sha, lines in tests_with_shas_to_create.items():
|
107
|
+
metadata, _ = SuiteMetadata.objects.get_or_create(
|
108
|
+
suite=suite.slug, name=name_with_sha, kind="test"
|
109
|
+
)
|
110
|
+
testrun.tests.create(
|
111
|
+
suite=suite,
|
112
|
+
result=False,
|
113
|
+
log="\n---\n".join(lines),
|
114
|
+
metadata=metadata,
|
115
|
+
build=testrun.build,
|
116
|
+
environment=testrun.environment,
|
117
|
+
)
|
118
|
+
|
119
|
+
def create_squad_tests(self, testrun, suite, test_name, lines, test_regex=None):
|
120
|
+
"""
|
121
|
+
There will be at least one test per regex. If there were any match for
|
122
|
+
a given regex, then a new test will be generated using test_name +
|
123
|
+
shasum. This helps comparing kernel logs across different builds
|
124
|
+
"""
|
125
|
+
tests_without_shas_to_create, tests_with_shas_to_create = (
|
126
|
+
self.create_name_log_dict(test_name, lines, test_regex)
|
127
|
+
)
|
128
|
+
self.create_squad_tests_from_name_log_dict(
|
129
|
+
suite,
|
130
|
+
testrun,
|
131
|
+
tests_without_shas_to_create,
|
132
|
+
tests_with_shas_to_create,
|
133
|
+
)
|
134
|
+
|
135
|
+
def join_matches(self, matches, regexes):
|
136
|
+
"""
|
137
|
+
group regex in python are returned as a list of tuples which each
|
138
|
+
group match in one of the positions in the tuple. Example:
|
139
|
+
regex = r'(a)|(b)|(c)'
|
140
|
+
matches = [
|
141
|
+
('match a', '', ''),
|
142
|
+
('', 'match b', ''),
|
143
|
+
('match a', '', ''),
|
144
|
+
('', '', 'match c')
|
145
|
+
]
|
146
|
+
"""
|
147
|
+
snippets = {regex_id: [] for regex_id in range(len(regexes))}
|
148
|
+
for match in matches:
|
149
|
+
for regex_id in range(len(regexes)):
|
150
|
+
if len(match[regex_id]) > 0:
|
151
|
+
snippets[regex_id].append(match[regex_id])
|
152
|
+
return snippets
|
@@ -1,18 +1,10 @@
|
|
1
|
-
import hashlib
|
2
1
|
import logging
|
3
2
|
import re
|
4
|
-
from collections import defaultdict
|
5
3
|
from squad.plugins import Plugin as BasePlugin
|
6
|
-
from squad.
|
7
|
-
from django.template.defaultfilters import slugify
|
8
|
-
|
4
|
+
from squad.plugins.lib.base_log_parser import BaseLogParser, REGEX_NAME, REGEX_EXTRACT_NAME
|
9
5
|
|
10
6
|
logger = logging.getLogger()
|
11
7
|
|
12
|
-
REGEX_NAME = 0
|
13
|
-
REGEX_BODY = 1
|
14
|
-
REGEX_EXTRACT_NAME = 2
|
15
|
-
|
16
8
|
MULTILINERS = [
|
17
9
|
('check-kernel-exception', r'-+\[? cut here \]?-+.*?-+\[? end trace \w* \]?-+', r"\d][^\+\n]*"),
|
18
10
|
('check-kernel-kasan', r'=+\n\[[\s\.\d]+\]\s+BUG: KASAN:.*?=+', r"BUG: KASAN:[^\+\n]*"),
|
@@ -32,11 +24,7 @@ ONELINERS = [
|
|
32
24
|
REGEXES = MULTILINERS + ONELINERS
|
33
25
|
|
34
26
|
|
35
|
-
class Plugin(BasePlugin):
|
36
|
-
def __compile_regexes(self, regexes):
|
37
|
-
combined = [r'(%s)' % r[REGEX_BODY] for r in regexes]
|
38
|
-
return re.compile(r'|'.join(combined), re.S | re.M)
|
39
|
-
|
27
|
+
class Plugin(BasePlugin, BaseLogParser):
|
40
28
|
def __cutoff_boot_log(self, log):
|
41
29
|
# Attempt to split the log in " login:"
|
42
30
|
logs = log.split(' login:', 1)
|
@@ -53,109 +41,6 @@ class Plugin(BasePlugin):
|
|
53
41
|
kernel_msgs = re.findall(r'(\[[ \d]+\.[ \d]+\] .*?)$', log, re.S | re.M)
|
54
42
|
return '\n'.join(kernel_msgs)
|
55
43
|
|
56
|
-
def __join_matches(self, matches, regexes):
|
57
|
-
"""
|
58
|
-
group regex in python are returned as a list of tuples which each
|
59
|
-
group match in one of the positions in the tuple. Example:
|
60
|
-
regex = r'(a)|(b)|(c)'
|
61
|
-
matches = [
|
62
|
-
('match a', '', ''),
|
63
|
-
('', 'match b', ''),
|
64
|
-
('match a', '', ''),
|
65
|
-
('', '', 'match c')
|
66
|
-
]
|
67
|
-
"""
|
68
|
-
snippets = {regex_id: [] for regex_id in range(len(regexes))}
|
69
|
-
for match in matches:
|
70
|
-
for regex_id in range(len(regexes)):
|
71
|
-
if len(match[regex_id]) > 0:
|
72
|
-
snippets[regex_id].append(match[regex_id])
|
73
|
-
return snippets
|
74
|
-
|
75
|
-
def __create_tests(self, testrun, suite, test_name, lines, test_regex=None):
|
76
|
-
"""
|
77
|
-
There will be at least one test per regex. If there were any match for a given
|
78
|
-
regex, then a new test will be generated using test_name + shasum. This helps
|
79
|
-
comparing kernel logs accross different builds
|
80
|
-
"""
|
81
|
-
# Run the REGEX_EXTRACT_NAME regex over the log lines to sort them by
|
82
|
-
# extracted name. If no name is extracted or the log parser did not
|
83
|
-
# have any output for a particular regex, just use the default name
|
84
|
-
# (for example "check-kernel-oops").
|
85
|
-
tests_to_create = defaultdict(set)
|
86
|
-
shas = defaultdict(set)
|
87
|
-
|
88
|
-
# If there are no lines, use the default name and create a passing
|
89
|
-
# test. For example "check-kernel-oops"
|
90
|
-
if not lines:
|
91
|
-
tests_to_create[test_name] = []
|
92
|
-
|
93
|
-
# If there are lines, then create the tests for these.
|
94
|
-
for line in lines:
|
95
|
-
extracted_name = self.__create_name(line, test_regex)
|
96
|
-
if extracted_name:
|
97
|
-
extended_test_name = f"{test_name}-{extracted_name}"
|
98
|
-
else:
|
99
|
-
extended_test_name = test_name
|
100
|
-
tests_to_create[extended_test_name].add(line)
|
101
|
-
|
102
|
-
for name, lines in tests_to_create.items():
|
103
|
-
metadata, _ = SuiteMetadata.objects.get_or_create(suite=suite.slug, name=name, kind='test')
|
104
|
-
testrun.tests.create(
|
105
|
-
suite=suite,
|
106
|
-
result=(len(lines) == 0),
|
107
|
-
log='\n'.join(lines),
|
108
|
-
metadata=metadata,
|
109
|
-
build=testrun.build,
|
110
|
-
environment=testrun.environment,
|
111
|
-
)
|
112
|
-
|
113
|
-
# Some lines of the matched regex might be the same, and we don't want to create
|
114
|
-
# multiple tests like test1-sha1, test1-sha1, etc, so we'll create a set of sha1sums
|
115
|
-
# then create only new tests for unique sha's
|
116
|
-
|
117
|
-
for line in lines:
|
118
|
-
sha = self.__create_shasum(line)
|
119
|
-
name_with_sha = f"{name}-{sha}"
|
120
|
-
shas[name_with_sha].add(line)
|
121
|
-
|
122
|
-
for name_with_sha, lines in shas.items():
|
123
|
-
metadata, _ = SuiteMetadata.objects.get_or_create(suite=suite.slug, name=name_with_sha, kind='test')
|
124
|
-
testrun.tests.create(
|
125
|
-
suite=suite,
|
126
|
-
result=False,
|
127
|
-
log='\n---\n'.join(lines),
|
128
|
-
metadata=metadata,
|
129
|
-
build=testrun.build,
|
130
|
-
environment=testrun.environment,
|
131
|
-
)
|
132
|
-
|
133
|
-
def __remove_numbers_and_time(self, snippet):
|
134
|
-
without_numbers = re.sub(r"(0x[a-f0-9]+|[<\[][0-9a-f]+?[>\]]|\d+)", "", snippet)
|
135
|
-
without_time = re.sub(r"^\[[^\]]+\]", "", without_numbers)
|
136
|
-
|
137
|
-
return without_time
|
138
|
-
|
139
|
-
def __create_name(self, snippet, regex=None):
|
140
|
-
matches = None
|
141
|
-
if regex:
|
142
|
-
matches = regex.findall(snippet)
|
143
|
-
if not matches:
|
144
|
-
return None
|
145
|
-
snippet = matches[0]
|
146
|
-
without_numbers_and_time = self.__remove_numbers_and_time(snippet)
|
147
|
-
|
148
|
-
# Limit the name length to 191 characters, since the max name length
|
149
|
-
# for SuiteMetadata in SQUAD is 256 characters. The SHA and "-" take 65
|
150
|
-
# characters: 256-65=191
|
151
|
-
return slugify(without_numbers_and_time)[:191]
|
152
|
-
|
153
|
-
def __create_shasum(self, snippet):
|
154
|
-
sha = hashlib.sha256()
|
155
|
-
without_numbers_and_time = self.__remove_numbers_and_time(snippet)
|
156
|
-
sha.update(without_numbers_and_time.encode())
|
157
|
-
return sha.hexdigest()
|
158
|
-
|
159
44
|
def postprocess_testrun(self, testrun):
|
160
45
|
if testrun.log_file is None:
|
161
46
|
return
|
@@ -170,9 +55,9 @@ class Plugin(BasePlugin):
|
|
170
55
|
log = self.__kernel_msgs_only(log)
|
171
56
|
suite, _ = testrun.build.project.suites.get_or_create(slug=f'log-parser-{log_type}')
|
172
57
|
|
173
|
-
regex = self.
|
58
|
+
regex = self.compile_regexes(REGEXES)
|
174
59
|
matches = regex.findall(log)
|
175
|
-
snippets = self.
|
60
|
+
snippets = self.join_matches(matches, REGEXES)
|
176
61
|
|
177
62
|
for regex_id in range(len(REGEXES)):
|
178
63
|
test_name = REGEXES[regex_id][REGEX_NAME]
|
@@ -180,4 +65,4 @@ class Plugin(BasePlugin):
|
|
180
65
|
test_name_regex = None
|
181
66
|
if regex_pattern:
|
182
67
|
test_name_regex = re.compile(regex_pattern, re.S | re.M)
|
183
|
-
self.
|
68
|
+
self.create_squad_tests(testrun, suite, test_name, snippets[regex_id], test_name_regex)
|
squad/settings.py
CHANGED
@@ -37,17 +37,21 @@ if not os.access(DATA_DIR, os.W_OK):
|
|
37
37
|
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
|
38
38
|
|
39
39
|
# SECURITY WARNING: keep the secret key used in production secret!
|
40
|
-
|
41
|
-
if
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
40
|
+
secret_key = os.getenv('SECRET_KEY', None)
|
41
|
+
if secret_key:
|
42
|
+
SECRET_KEY = secret_key
|
43
|
+
else:
|
44
|
+
secret_key_file = os.getenv('SECRET_KEY_FILE', None)
|
45
|
+
if secret_key_file is None:
|
46
|
+
secret_key_file = os.path.join(DATA_DIR, 'secret.dat')
|
47
|
+
|
48
|
+
if not os.path.exists(secret_key_file):
|
49
|
+
from squad.core.utils import random_key
|
50
|
+
fd = os.open(secret_key_file, os.O_WRONLY | os.O_CREAT, 0o600)
|
51
|
+
with os.fdopen(fd, 'w') as f:
|
52
|
+
f.write(random_key(64))
|
53
|
+
|
54
|
+
SECRET_KEY = open(secret_key_file).read()
|
51
55
|
|
52
56
|
DEBUG = os.getenv('ENV') not in ['production', 'staging']
|
53
57
|
|
squad/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '1.
|
1
|
+
__version__ = '1.90'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: squad
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.90
|
4
4
|
Summary: Software Quality Dashboard
|
5
5
|
Home-page: https://github.com/Linaro/squad
|
6
6
|
Author: Antonio Terceiro
|
@@ -12,26 +12,26 @@ Requires-Dist: aiohttp
|
|
12
12
|
Requires-Dist: celery
|
13
13
|
Requires-Dist: cryptography
|
14
14
|
Requires-Dist: coreapi
|
15
|
-
Requires-Dist: django-crispy-forms
|
16
|
-
Requires-Dist: Django
|
15
|
+
Requires-Dist: django-crispy-forms==1.14.0
|
16
|
+
Requires-Dist: Django>=3
|
17
17
|
Requires-Dist: django-allauth
|
18
18
|
Requires-Dist: django-bootstrap3
|
19
19
|
Requires-Dist: django-celery-results
|
20
20
|
Requires-Dist: django-cors-headers
|
21
21
|
Requires-Dist: django-debug-toolbar
|
22
|
-
Requires-Dist: django-simple-history
|
23
|
-
Requires-Dist: django-filter
|
24
|
-
Requires-Dist: djangorestframework
|
25
|
-
Requires-Dist: djangorestframework-filters
|
22
|
+
Requires-Dist: django-simple-history>3.0
|
23
|
+
Requires-Dist: django-filter>=2.0
|
24
|
+
Requires-Dist: djangorestframework>=3.9.2
|
25
|
+
Requires-Dist: djangorestframework-filters>=1.0.0.dev0
|
26
26
|
Requires-Dist: drf-extensions
|
27
27
|
Requires-Dist: future
|
28
28
|
Requires-Dist: gunicorn
|
29
|
-
Requires-Dist: importlib-metadata
|
30
|
-
Requires-Dist: Jinja2
|
29
|
+
Requires-Dist: importlib-metadata>3
|
30
|
+
Requires-Dist: Jinja2==3.0.3
|
31
31
|
Requires-Dist: Markdown
|
32
|
-
Requires-Dist: msgpack
|
32
|
+
Requires-Dist: msgpack>=0.5.0
|
33
33
|
Requires-Dist: python-dateutil
|
34
|
-
Requires-Dist: PyYAML
|
34
|
+
Requires-Dist: PyYAML>=5.1
|
35
35
|
Requires-Dist: PyJWT
|
36
36
|
Requires-Dist: pyzmq
|
37
37
|
Requires-Dist: requests
|
@@ -40,6 +40,7 @@ Requires-Dist: sqlparse
|
|
40
40
|
Requires-Dist: svgwrite
|
41
41
|
Requires-Dist: whitenoise
|
42
42
|
Provides-Extra: postgres
|
43
|
-
Requires-Dist: psycopg2
|
43
|
+
Requires-Dist: psycopg2; extra == "postgres"
|
44
44
|
|
45
45
|
Software Quality Dashboard
|
46
|
+
|
@@ -7,10 +7,10 @@ squad/http.py,sha256=KuIKtpf3yOvf5fwc0T2MR0ul1l4AKxq3b0CLdk6KBhM,3667
|
|
7
7
|
squad/jinja2.py,sha256=OKX-lzNz6qtTZL56HWv4UBMPuBl4WQXv0qFJztGp9zs,2541
|
8
8
|
squad/mail.py,sha256=xH5wuIpD7u1fTN9vNOcbzByojleaffsKwp-9i3BeOD0,390
|
9
9
|
squad/manage.py,sha256=Z-LXT67p0R-IzwJ9fLIAacEZmU0VUjqDOSg7j2ZSxJ4,1437
|
10
|
-
squad/settings.py,sha256=
|
10
|
+
squad/settings.py,sha256=nx_cXfFOf3i5z7bmIzwkRhBgVHWtDBfK40-yo5hQUzw,14663
|
11
11
|
squad/socialaccount.py,sha256=vySqPwQ3qVVpahuJ-Snln8K--yzRL3bw4Nx27AsB39A,789
|
12
12
|
squad/urls.py,sha256=JiEfVW8YlzLPE52c2aHzdn5kVVKK4o22w8h5KOA6QhQ,2776
|
13
|
-
squad/version.py,sha256=
|
13
|
+
squad/version.py,sha256=xCyEItfDbvgP8ttkgjhTpQfmnJCsuxMtkuIMOjALn54,21
|
14
14
|
squad/wsgi.py,sha256=SF8T0cQ0OPVyuYjO5YXBIQzvSXQHV0M2BTmd4gP1rPs,387
|
15
15
|
squad/api/__init__.py,sha256=CJiVakfAlHVN5mIFRVQYZQfuNUhUgWVbsdYTME4tq7U,1349
|
16
16
|
squad/api/apps.py,sha256=Trk72p-iV1uGn0o5mdJn5HARUoHGbfgO49jwXvpkmdQ,141
|
@@ -20,7 +20,7 @@ squad/api/filters.py,sha256=Zvp8DCJmiNquFWqvfVseEAAMYYPiT95RUjqKdzcqSnw,6917
|
|
20
20
|
squad/api/rest.py,sha256=ZtbK0c1BLPPnsX79XlKFVYONM_VJ0vacWZ2JsdCd4l0,77342
|
21
21
|
squad/api/urls.py,sha256=rmsdaL1uOCVSZ5x1redup9RliICmijaBjRK5ObsTkG8,1343
|
22
22
|
squad/api/utils.py,sha256=Sa8QFId3_oSqD2UOoY3Kuh54LLDLPNMq2sub5ktd6Fs,1160
|
23
|
-
squad/api/views.py,sha256=
|
23
|
+
squad/api/views.py,sha256=WH4c10e7iRmuL5tWDxG4zEFHzvF5hxDpEVvybfvbc_E,3880
|
24
24
|
squad/ci/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
25
25
|
squad/ci/admin.py,sha256=7yB-6F0cvt0NVvzGOTlZCyGPV_YHarmbKJZTTzataT4,2255
|
26
26
|
squad/ci/apps.py,sha256=6OVnzTdJkxdqEJnKWYE9dZgUcc29_T1LrDw41cK4EQk,139
|
@@ -81,12 +81,12 @@ squad/core/comparison.py,sha256=LR3-Unv0CTmakFCDzF_h8fm2peTJzkv79mQWNau1iwI,2442
|
|
81
81
|
squad/core/data.py,sha256=2zw56v7iYRTUc7wlhuUNgwIIMmK2w84hi-amR9J7EPU,2236
|
82
82
|
squad/core/failures.py,sha256=X6lJVghM2fOrd-RfuHeLlezW2pt7owDZ8eX-Kn_Qrt0,918
|
83
83
|
squad/core/history.py,sha256=QRSIoDOw6R6vUWMtsPMknsHGM7FaCAeuCYqASCayHTk,3541
|
84
|
-
squad/core/models.py,sha256=
|
84
|
+
squad/core/models.py,sha256=sXQmgPtl54IZT7rDmJEU3QK6JSPbi0hTUGRsjwL6PIo,60851
|
85
85
|
squad/core/notification.py,sha256=rOpO6F63w7_5l9gQgWBBEk-MFBjp7x_hVzoVIVyDze0,10030
|
86
86
|
squad/core/plugins.py,sha256=FLgyoXXKnPBYEf2MgHup9M017rHuADHivLhgzmx_cJE,6354
|
87
87
|
squad/core/queries.py,sha256=78fhIJZWXIlDryewYAt96beK1VJad66Ufu8cg3dHh4w,7698
|
88
88
|
squad/core/statistics.py,sha256=xyTHuhdBjcJ4AozZESjTzSD3dBmmCDgLpbg5XpeyO_M,1056
|
89
|
-
squad/core/utils.py,sha256=
|
89
|
+
squad/core/utils.py,sha256=HwCq8SsKJHbBUtF4DZt1iWCuWhqZaHRBn--Yh0O_RH4,5018
|
90
90
|
squad/core/locale/django.pot,sha256=XycSJyEaEpozGBS9zu7QTNQbffZC0D9eSJ-AwXaVZx4,2282
|
91
91
|
squad/core/locale/es_MX/LC_MESSAGES/django.po,sha256=bwvTWHK2KOT6zFqbIYh61_xYqRnMaQECZsMsOvNdMNw,3071
|
92
92
|
squad/core/locale/pl/LC_MESSAGES/django.po,sha256=mI-Vo8OKWCcx4PrsoB6GiPY3lYU55tSqh0sO6fUeK2Y,3111
|
@@ -98,7 +98,7 @@ squad/core/management/commands/compute_build_summaries.py,sha256=dz6-3vXtFNGYOzl
|
|
98
98
|
squad/core/management/commands/compute_project_statuses.py,sha256=qcm71zEP_A-XhNWrDHM55TJSgKUk_oWjewuZEu2B2KM,3134
|
99
99
|
squad/core/management/commands/fill_test_metadata.py,sha256=EG2mqKtThY5D7nnGalM3q0XOPEVDiDnFLV7sw7YSz1U,1326
|
100
100
|
squad/core/management/commands/fix_squadplugin_data.py,sha256=cbjPL_-AvazBsmXKd5x6LpaoP-3MGpa3uoUUxljVzdw,5072
|
101
|
-
squad/core/management/commands/import_data.py,sha256=
|
101
|
+
squad/core/management/commands/import_data.py,sha256=KgSTNtrQQiqzqjJdvKDHbU6IExPsdTbdMJ-yqfZY4Y4,4556
|
102
102
|
squad/core/management/commands/import_data.rst,sha256=79tAcJ6hOVRVzW2iheQuO6o2RHZKbbFtsHM-IEr6490,1444
|
103
103
|
squad/core/management/commands/migrate_test_runs.py,sha256=RHV06tb4gWyv_q-ooC821_QGZi0WGwxjIYaUGTboqfI,4214
|
104
104
|
squad/core/management/commands/populate_metric_build_and_environment.py,sha256=DJP9_YLRso0RiERBVsB0GP4-GaiRtJb0rAiUQDfFNQk,3166
|
@@ -277,7 +277,7 @@ squad/core/migrations/0167_add_project_datetime.py,sha256=VUBG-qsAhh2f2NXaHOqfX9
|
|
277
277
|
squad/core/migrations/0168_add_group_settings.py,sha256=5UdylfMMNavTL0KXkjPSiEMhSisGWXbhUXQSzfK29Ck,462
|
278
278
|
squad/core/migrations/0169_userpreferences.py,sha256=FwYv9RWxMWdQ2lXJMgi-Xc6XBB5Kp-_YTAOr9GVq1To,1098
|
279
279
|
squad/core/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
280
|
-
squad/core/tasks/__init__.py,sha256=
|
280
|
+
squad/core/tasks/__init__.py,sha256=pYbEkFzNaat7iQQretRiJQPPF4Sq-5-hBykJYnBM04g,18567
|
281
281
|
squad/core/tasks/exceptions.py,sha256=n4cbmJFBdA6KWsGiTbfN9DyYGbJpk0DjR0UneEYw_W0,931
|
282
282
|
squad/core/tasks/notification.py,sha256=6ZyTbUQZPITPP-4r9MUON7x-NbwvDBG8YeabM6fsjzA,4915
|
283
283
|
squad/core/templates/squad/notification/base.jinja2,sha256=AbtQioEHV5DJBW4Etsu0-DQXd_8tQCnLejzgbDGDW7s,3413
|
@@ -425,15 +425,17 @@ squad/plugins/__init__.py,sha256=9BSzy2jFIoDpWlhD7odPPrLdW4CC3btBhdFCvB651dM,152
|
|
425
425
|
squad/plugins/example.py,sha256=BKpwd315lHRIuNXJPteibpwfnI6C5eXYHYdFYBtVmsI,89
|
426
426
|
squad/plugins/gerrit.py,sha256=CqO2KnFQzu9utr_TQ-sGr1wg3ln0B-bS2-c0_i8T5-c,7009
|
427
427
|
squad/plugins/github.py,sha256=pdtLZw_7xNuzkaFvY_zWi0f2rsMlalXjKm7sz0eADz4,2429
|
428
|
-
squad/plugins/linux_log_parser.py,sha256=
|
428
|
+
squad/plugins/linux_log_parser.py,sha256=9vjt3z7ZDYofR90-JZv260phKMJyRv3sdksr8satgi0,2662
|
429
|
+
squad/plugins/lib/__init__.py,sha256=jzazbAvp2_ibblAs0cKZrmo9aR2EL3hKLyRDE008r2I,40
|
430
|
+
squad/plugins/lib/base_log_parser.py,sha256=lfGoHWYTzOmWxME-qGArpJatzjUdy0uEII5eokDfP1Y,6189
|
429
431
|
squad/run/__init__.py,sha256=ssE8GPAGFiK6V0WpZYowav6Zqsd63dfDMMYasNa1sQg,1410
|
430
432
|
squad/run/__main__.py,sha256=DOl8JOi4Yg7DdtwnUeGqtYBJ6P2k-D2psAEuYOjWr8w,66
|
431
433
|
squad/run/listener.py,sha256=jBeOQhPGb4EdIREB1QsCzYuumsfJ-TqJPd3nR-0m59g,200
|
432
434
|
squad/run/scheduler.py,sha256=CDJG3q5C0GuQuxwlMOfWTSSJpDdwbR6rzpbJfuA0xuw,277
|
433
435
|
squad/run/worker.py,sha256=jtML0h5qKDuSbpJ6_rpWP4MT_rsGA7a24AhwGxBquzk,594
|
434
|
-
squad-1.
|
435
|
-
squad-1.
|
436
|
-
squad-1.
|
437
|
-
squad-1.
|
438
|
-
squad-1.
|
439
|
-
squad-1.
|
436
|
+
squad-1.90.dist-info/COPYING,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
|
437
|
+
squad-1.90.dist-info/METADATA,sha256=wn7qXz18DRF1uk_WM5Fh_TjO8RxUg-eanVQnfmjbKVk,1271
|
438
|
+
squad-1.90.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
439
|
+
squad-1.90.dist-info/entry_points.txt,sha256=J_jG3qnkoOHX4RFNGC0f83eJ4BSvK3pqLFkoF3HWfmA,195
|
440
|
+
squad-1.90.dist-info/top_level.txt,sha256=_x9uqE1XppiiytmVTl_qNgpnXus6Gsef69HqfliE7WI,6
|
441
|
+
squad-1.90.dist-info/RECORD,,
|
File without changes
|
File without changes
|