squad 1.90__py3-none-any.whl → 1.92__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/ci.py CHANGED
@@ -73,15 +73,26 @@ def submit_job(request, group_slug, project_slug, version, environment_slug):
73
73
  @csrf_exempt
74
74
  @auth_privileged
75
75
  def watch_job(request, group_slug, project_slug, version, environment_slug):
76
+
77
+ # testjob_id points to the backend's test job
78
+ testjob_id = request.POST.get('testjob_id', None)
79
+ if testjob_id is None:
80
+ return HttpResponseBadRequest("testjob_id is required")
81
+
76
82
  backend_name = request.POST.get('backend')
77
83
  if backend_name is None:
78
84
  return HttpResponseBadRequest("backend field is required")
85
+
79
86
  backend = None
80
87
  try:
81
88
  backend = Backend.objects.get(name=request.POST.get('backend'))
82
89
  except Backend.DoesNotExist:
83
90
  return HttpResponseBadRequest("requested backend does not exist")
84
91
 
92
+ check = backend.get_implementation().check_job_id(testjob_id)
93
+ if check is not True:
94
+ return HttpResponseBadRequest(check)
95
+
85
96
  # project has to exist or request will result with 400
86
97
  project = request.project
87
98
  if backend is None or project is None:
@@ -90,12 +101,6 @@ def watch_job(request, group_slug, project_slug, version, environment_slug):
90
101
  # create Build object
91
102
  build, _ = project.builds.get_or_create(version=version)
92
103
 
93
- # testjob_id points to the backend's test job
94
- testjob_id = request.POST.get('testjob_id', None)
95
-
96
- if testjob_id is None:
97
- return HttpResponseBadRequest("testjob_id is required")
98
-
99
104
  # create TestJob object
100
105
  test_job = TestJob(
101
106
  backend=backend,
@@ -0,0 +1,52 @@
1
+ import re
2
+ import requests
3
+ import celery
4
+
5
+ from django.conf import settings
6
+ from django.http import HttpResponse, HttpResponseForbidden
7
+ from django.views.decorators.csrf import csrf_exempt
8
+ from django.views.decorators.http import require_http_methods
9
+
10
+ from squad.http import auth_user_from_request
11
+
12
+
13
+ @csrf_exempt
14
+ @require_http_methods(['GET'])
15
+ def metrics(request):
16
+ user = auth_user_from_request(request, request.user)
17
+ if not user.is_authenticated:
18
+ return HttpResponseForbidden()
19
+
20
+ output = ''
21
+ available_queues = None
22
+
23
+ active_queues = celery.current_app.control.inspect().active_queues()
24
+ if active_queues is not None:
25
+ active_workers = set()
26
+ available_queues = set()
27
+ for worker_name, queues in active_queues.items():
28
+ active_workers.add(worker_name)
29
+ available_queues |= set([q['name'] for q in queues])
30
+
31
+ output += '# TYPE workers_count counter\n'
32
+ output += f'workers_count {len(active_workers)}\n'
33
+
34
+ # TODO: check how to get metrics for non-RabbitMQ brokers
35
+ if settings.CELERY_BROKER_URL:
36
+ rabbitmq_url = settings.CELERY_BROKER_URL.replace('amqps://', 'https://').replace('amqp://', 'http://')
37
+ rabbitmq_url = re.sub(r':\d+$', '', rabbitmq_url)
38
+ rabbitmq_url += '/api/queues'
39
+
40
+ response = requests.get(rabbitmq_url)
41
+ queues = response.json()
42
+ available_queues = {r["queue"] for r in settings.CELERY_TASK_ROUTES.values()}
43
+
44
+ for queue in queues:
45
+ if queue['name'] in available_queues:
46
+ metric_name = f'queue_{queue["name"]}_count'
47
+ length = queue['messages_ready']
48
+
49
+ output += f'\n# TYPE {metric_name} counter'
50
+ output += f'\n{metric_name} {length}'
51
+
52
+ return HttpResponse(output, status=200, content_type="text/plain;")
squad/api/urls.py CHANGED
@@ -5,6 +5,7 @@ from rest_framework.schemas import get_schema_view
5
5
  from . import views
6
6
  from . import data
7
7
  from . import ci
8
+ from . import prometheus
8
9
  from . import rest
9
10
 
10
11
 
@@ -26,4 +27,5 @@ urlpatterns = [
26
27
  url(r'^resubmit/([0-9]+)', ci.resubmit_job),
27
28
  url(r'^forceresubmit/([0-9]+)', ci.force_resubmit_job),
28
29
  url(r'^version/', views.version),
30
+ url(r'^prometheus/', prometheus.metrics),
29
31
  ]
squad/ci/backend/fake.py CHANGED
@@ -72,6 +72,9 @@ class Backend(object):
72
72
  def check_job_definition(self, definition):
73
73
  return True
74
74
 
75
+ def check_job_id(self, job_id):
76
+ return True
77
+
75
78
  def get_job_definition(self, test_job):
76
79
  return "sample job definition"
77
80
 
squad/ci/backend/lava.py CHANGED
@@ -683,7 +683,7 @@ class Backend(BaseBackend):
683
683
  if clone_measurements_to_tests:
684
684
  res_value = result['result']
685
685
  results.update({res_name: res_value})
686
- elif result['name'] == 'auto-login-action' and handle_lava_boot:
686
+ elif 'login-action' in result['name'] and handle_lava_boot:
687
687
  # add artificial 'boot' test result for each test job
688
688
  # by default the boot test is named after the device_type
689
689
  boot = "boot-%s" % test_job.name
@@ -785,6 +785,11 @@ class Backend(BaseBackend):
785
785
  except yaml.YAMLError as e:
786
786
  return str(e)
787
787
 
788
+ def check_job_id(self, job_id):
789
+ if re.match(r"^\d+$", str(job_id)) is not None:
790
+ return True
791
+ return "LAVA job id should be an integer"
792
+
788
793
  def get_job_definition(self, job_id):
789
794
  if self.use_xml_rpc:
790
795
  return self.proxy.scheduler.jobs.definition(job_id)
squad/ci/backend/null.py CHANGED
@@ -143,6 +143,12 @@ class Backend:
143
143
  """
144
144
  raise NotImplementedError
145
145
 
146
+ def check_job_id(self, job_id):
147
+ """
148
+ Returns True if job id matches what the backend expect, else returns the error message
149
+ """
150
+ raise NotImplementedError
151
+
146
152
  def format_message(self, msg):
147
153
  if self.data and hasattr(self.data, "name"):
148
154
  return self.data.name + ': ' + msg
@@ -120,6 +120,13 @@ class Backend(BaseBackend):
120
120
  # The regex below is supposed to find only one match
121
121
  return matches[0]
122
122
 
123
+ def check_job_id(self, job_id):
124
+ try:
125
+ self.parse_job_id(job_id)
126
+ return True
127
+ except FetchIssue as e:
128
+ return str(e)
129
+
123
130
  def generate_job_id(self, result_type, result):
124
131
  """
125
132
  The job id for TuxSuite results is generated using 3 pieces of info:
@@ -144,7 +151,11 @@ class Backend(BaseBackend):
144
151
  url = reduce(urljoin, urlbits)
145
152
 
146
153
  try:
147
- response = Backend.get_session().request("GET", url)
154
+ headers = {}
155
+ if hasattr(self, 'auth_token') and self.auth_token is not None:
156
+ headers = {'Authorization': self.auth_token}
157
+
158
+ response = Backend.get_session().request("GET", url, headers=headers)
148
159
  except Exception as e:
149
160
  raise TemporaryFetchIssue(f"Can't retrieve from {url}: {e}")
150
161
 
@@ -224,6 +235,11 @@ class Backend(BaseBackend):
224
235
  if 'toolchain' in build_metadata_keys and 'kconfig' in build_metadata_keys and metadata['build_name'] in [None, '']:
225
236
  metadata['build_name'] = self.generate_test_name(build_metadata)
226
237
 
238
+ def add_skip_boot_test(self, tests, metadata):
239
+ # Create an artificial boot test and mark it as skip
240
+ boot_test_name = 'boot/' + (metadata.get('build_name') or 'boot')
241
+ tests[boot_test_name] = None
242
+
227
243
  def parse_build_results(self, test_job, job_url, results, settings):
228
244
  required_keys = ['build_status', 'warnings_count', 'download_url', 'retry']
229
245
  self.__check_required_keys__(required_keys, results)
@@ -233,9 +249,6 @@ class Backend(BaseBackend):
233
249
  test_job.name = test_name
234
250
 
235
251
  build_status = results['build_status']
236
- if build_status == 'error' and results['retry'] < 2:
237
- # SQUAD should retry fetching the build until retry == 2
238
- raise TemporaryFetchIssue(results.get('status_message', 'TuxSuite Error'))
239
252
 
240
253
  # Make metadata
241
254
  metadata_keys = settings.get('BUILD_METADATA_KEYS', [])
@@ -254,7 +267,7 @@ class Backend(BaseBackend):
254
267
  metrics = {}
255
268
 
256
269
  completed = True
257
- if results['retry'] >= 2:
270
+ if build_status == 'error':
258
271
  # This indicates that TuxSuite gave up trying to work on this build
259
272
  status = 'Incomplete'
260
273
  tests[f'build/{test_name}'] = 'skip'
@@ -318,6 +331,11 @@ class Backend(BaseBackend):
318
331
  metadata_keys = settings.get('TEST_METADATA_KEYS', [])
319
332
  metadata = {k: results.get(k) for k in metadata_keys}
320
333
 
334
+ # Change environment name
335
+ if 'test_name' in results and results.get('test_name') is not None:
336
+ test_job.environment = results.get('test_name')
337
+ test_job.save()
338
+
321
339
  # Add extra metadata from metadata file if it exists
322
340
  self.update_metadata_from_file(results=results, metadata=metadata)
323
341
 
@@ -340,6 +358,8 @@ class Backend(BaseBackend):
340
358
  else:
341
359
  test_job.failure = 'sanity test failed'
342
360
 
361
+ self.add_skip_boot_test(tests, metadata)
362
+
343
363
  return status, completed, metadata, tests, metrics, logs
344
364
 
345
365
  # Fetch results even if the job fails, but has results
@@ -348,8 +368,14 @@ class Backend(BaseBackend):
348
368
 
349
369
  elif results['result'] == 'error':
350
370
  test_job.failure = 'tuxsuite infrastructure error'
371
+ self.add_skip_boot_test(tests, metadata)
351
372
  return 'Incomplete', completed, metadata, tests, metrics, logs
352
373
 
374
+ elif results['result'] == 'canceled':
375
+ test_job.failure = 'tuxsuite job canceled'
376
+ self.add_skip_boot_test(tests, metadata)
377
+ return 'Canceled', completed, metadata, tests, metrics, logs
378
+
353
379
  # If boot result is unkown, a retry is needed, otherwise, it either passed or failed
354
380
  if 'unknown' == results['results']['boot']:
355
381
  return None
@@ -384,6 +410,10 @@ class Backend(BaseBackend):
384
410
 
385
411
  def fetch(self, test_job):
386
412
  url = self.job_url(test_job)
413
+
414
+ settings = self.__resolve_settings__(test_job)
415
+ self.auth_token = settings.get('TUXSUITE_TOKEN', None)
416
+
387
417
  if test_job.input:
388
418
  results = self.fetch_from_results_input(test_job)
389
419
  test_job.input = None
@@ -393,11 +423,12 @@ class Backend(BaseBackend):
393
423
  if results.get('state') != 'finished':
394
424
  return None
395
425
 
396
- settings = self.__resolve_settings__(test_job)
397
-
398
426
  result_type = self.parse_job_id(test_job.job_id)[0]
399
427
  parse_results = getattr(self, f'parse_{result_type.lower()}_results')
400
- return parse_results(test_job, url, results, settings)
428
+ parsed = parse_results(test_job, url, results, settings)
429
+
430
+ self.auth_token = None
431
+ return parsed
401
432
 
402
433
  def job_url(self, test_job):
403
434
  result_type, tux_project, tux_uid = self.parse_job_id(test_job.job_id)
@@ -6,6 +6,14 @@
6
6
 
7
7
  {% include "squad/project-nav.jinja2" %}
8
8
 
9
+
10
+ {% if project.description%}
11
+ <h2>{{ _('Description') }}</h2>
12
+ <div class='description-{{project.id}}'>
13
+ {{project.description}}
14
+ </div>
15
+ {% endif %}
16
+
9
17
  {% if last_build %}
10
18
  <div>
11
19
  <h2>
squad/frontend/urls.py CHANGED
@@ -52,6 +52,7 @@ urlpatterns = [
52
52
  url(r'^(%s)/(%s)/build/([^/]+)/attachments/testrun/([^/]+)/([^/]+)$' % group_and_project, views.build_attachment, name='build_attachments'),
53
53
  url(r'^(%s)/(%s)/build/([^/]+)/testrun/([^/]+)/suite/([^/]+)/tests/$' % group_and_project, views.test_run_suite_tests, name='testrun_suite_tests'),
54
54
  url(r'^(%s)/(%s)/build/([^/]+)/testrun/([^/]+)/suite/([^/]+)/test/([^/]+)/history/$' % group_and_project, tests.test_history, name='test_history'),
55
+ url(r'^(%s)/(%s)/build/([^/]+)/testrun/([^/]+)/suite/([^/]+)/test/([^/]+)/$' % group_and_project, views.test_run_suite_test_details, name='testrun_suite_test_details'),
55
56
  url(r'^(%s)/(%s)/build/([^/]+)/testrun/([^/]+)/suite/([^/]+)/test/([^/]+)/details/$' % group_and_project, views.test_run_suite_test_details, name='testrun_suite_test_details'),
56
57
  url(r'^(%s)/(%s)/build/([^/]+)/testrun/([^/]+)/suite/([^/]+)/metrics/$' % group_and_project, views.test_run_suite_metrics, name='testrun_suite_metrics'),
57
58
  url(r'^(%s)/(%s)/build/([^/]+)/testrun/([^/]+)/suite/([^/]+)/test/([^/]+)/log$' % group_and_project, views.test_details_log, name='test_details_log'),
@@ -8,6 +8,11 @@ REGEX_NAME = 0
8
8
  REGEX_BODY = 1
9
9
  REGEX_EXTRACT_NAME = 2
10
10
 
11
+ tstamp = r"\[[ \d]+\.[ \d]+\]"
12
+ pid = r"(?:\s*?\[\s*?[CT]\d+\s*?\])"
13
+ not_newline_or_plus = r"[^\+\n]"
14
+ square_brackets_and_contents = r"\[[^\]]+\]"
15
+
11
16
 
12
17
  class BaseLogParser:
13
18
  def compile_regexes(self, regexes):
@@ -15,8 +20,13 @@ class BaseLogParser:
15
20
  return re.compile(r"|".join(combined), re.S | re.M)
16
21
 
17
22
  def remove_numbers_and_time(self, snippet):
23
+ # [ 1067.461794][ T132] BUG: KCSAN: data-race in do_page_fault spectre_v4_enable_task_mitigation
24
+ # -> [ .][ T] BUG: KCSAN: data-race in do_page_fault spectre_v_enable_task_mitigation
18
25
  without_numbers = re.sub(r"(0x[a-f0-9]+|[<\[][0-9a-f]+?[>\]]|\d+)", "", snippet)
19
- without_time = re.sub(r"^\[[^\]]+\]", "", without_numbers)
26
+
27
+ # [ .][ T] BUG: KCSAN: data-race in do_page_fault spectre_v_enable_task_mitigation
28
+ # -> BUG: KCSAN: data-race in do_page_fault spectre_v_enable_task_mitigation
29
+ without_time = re.sub(f"^{square_brackets_and_contents}({square_brackets_and_contents})?", "", without_numbers) # noqa
20
30
 
21
31
  return without_time
22
32
 
@@ -56,11 +66,6 @@ class BaseLogParser:
56
66
  tests_without_shas_to_create = defaultdict(set)
57
67
  tests_with_shas_to_create = defaultdict(set)
58
68
 
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
69
  # If there are lines, then create the tests for these.
65
70
  for line in lines:
66
71
  extracted_name = self.create_name(line, test_regex)
@@ -1,23 +1,26 @@
1
1
  import logging
2
2
  import re
3
3
  from squad.plugins import Plugin as BasePlugin
4
- from squad.plugins.lib.base_log_parser import BaseLogParser, REGEX_NAME, REGEX_EXTRACT_NAME
4
+ from squad.plugins.lib.base_log_parser import BaseLogParser, REGEX_NAME, REGEX_EXTRACT_NAME, tstamp, pid, not_newline_or_plus
5
5
 
6
6
  logger = logging.getLogger()
7
7
 
8
8
  MULTILINERS = [
9
- ('check-kernel-exception', r'-+\[? cut here \]?-+.*?-+\[? end trace \w* \]?-+', r"\d][^\+\n]*"),
10
- ('check-kernel-kasan', r'=+\n\[[\s\.\d]+\]\s+BUG: KASAN:.*?=+', r"BUG: KASAN:[^\+\n]*"),
11
- ('check-kernel-kfence', r'=+\n\[[\s\.\d]+\]\s+BUG: KFENCE:.*?=+', r"BUG: KFENCE:[^\+\n]*"),
9
+ ('exception', fr'-+\[? cut here \]?-+.*?{tstamp}{pid}?\s+-+\[? end trace \w* \]?-+', fr"\n{tstamp}{not_newline_or_plus}*"), # noqa
10
+ ('kasan', fr'{tstamp}{pid}?\s+=+\n{tstamp}{pid}?\s+BUG: KASAN:.*?\n*?{tstamp}{pid}?\s+=+', fr"BUG: KASAN:{not_newline_or_plus}*"), # noqa
11
+ ('kcsan', fr'{tstamp}{pid}?\s+=+\n{tstamp}{pid}?\s+BUG: KCSAN:.*?=+', fr"BUG: KCSAN:{not_newline_or_plus}*"), # noqa
12
+ ('kfence', fr'{tstamp}{pid}?\s+=+\n{tstamp}{pid}?\s+BUG: KFENCE:.*?{tstamp}{pid}?\s+=+', fr"BUG: KFENCE:{not_newline_or_plus}*"), # noqa
13
+ ('panic-multiline', fr'{tstamp}{pid}?\s+Kernel panic - [^\n]+\n.*?-+\[? end Kernel panic - [^\n]+ \]?-*', fr"Kernel {not_newline_or_plus}*"), # noqa
14
+ ('internal-error-oops', fr'{tstamp}{pid}?\s+Internal error: Oops.*?-+\[? end trace \w+ \]?-+', fr"Oops{not_newline_or_plus}*"), # noqa
12
15
  ]
13
16
 
14
17
  ONELINERS = [
15
- ('check-kernel-oops', r'^[^\n]+Oops(?: -|:).*?$', r"Oops[^\+\n]*"),
16
- ('check-kernel-fault', r'^[^\n]+Unhandled fault.*?$', r"Unhandled [^\+\n]*"),
17
- ('check-kernel-warning', r'^[^\n]+WARNING:.*?$', r"WARNING: [^\+\n]*"),
18
- ('check-kernel-bug', r'^[^\n]+(?: kernel BUG at|BUG:).*?$', r"BUG[^\+\n]*"),
19
- ('check-kernel-invalid-opcode', r'^[^\n]+invalid opcode:.*?$', r"invalid opcode: [^\+\n]*"),
20
- ('check-kernel-panic', r'Kernel panic - not syncing.*?$', r"Kernel [^\+\n]*"),
18
+ ('oops', r'^[^\n]+Oops(?: -|:).*?$', fr"Oops{not_newline_or_plus}*"), # noqa
19
+ ('fault', r'^[^\n]+Unhandled fault.*?$', fr"Unhandled {not_newline_or_plus}*"), # noqa
20
+ ('warning', r'^[^\n]+WARNING:.*?$', fr"WARNING:{not_newline_or_plus}*"), # noqa
21
+ ('bug', r'^[^\n]+(?: kernel BUG at|BUG:).*?$', fr"BUG{not_newline_or_plus}*"), # noqa
22
+ ('invalid-opcode', r'^[^\n]+invalid opcode:.*?$', fr"invalid opcode:{not_newline_or_plus}*"), # noqa
23
+ ('panic', r'Kernel panic - not syncing.*?$', fr"Kernel {not_newline_or_plus}*"), # noqa
21
24
  ]
22
25
 
23
26
  # Tip: broader regexes should come first
@@ -38,7 +41,7 @@ class Plugin(BasePlugin, BaseLogParser):
38
41
  return boot_log, test_log
39
42
 
40
43
  def __kernel_msgs_only(self, log):
41
- kernel_msgs = re.findall(r'(\[[ \d]+\.[ \d]+\] .*?)$', log, re.S | re.M)
44
+ kernel_msgs = re.findall(f'({tstamp}{pid}? .*?)$', log, re.S | re.M) # noqa
42
45
  return '\n'.join(kernel_msgs)
43
46
 
44
47
  def postprocess_testrun(self, testrun):
squad/settings.py CHANGED
@@ -422,6 +422,7 @@ CRISPY_TEMPLATE_PACK = 'bootstrap3'
422
422
 
423
423
  # Sentry support
424
424
  SENTRY_DSN = os.getenv('SENTRY_DSN')
425
+ SENTRY_TRACES_SAMPLE_RATE = os.getenv('SENTRY_TRACES_SAMPLE_RATE', '0')
425
426
  if SENTRY_DSN:
426
427
  try:
427
428
  import sentry_sdk
@@ -432,6 +433,7 @@ if SENTRY_DSN:
432
433
  dsn=SENTRY_DSN,
433
434
  integrations=[DjangoIntegration(), CeleryIntegration()],
434
435
  release='%s@%s' % (os.getenv('ENV', 'squad'), squad_version),
436
+ traces_sample_rate=float(SENTRY_TRACES_SAMPLE_RATE),
435
437
  )
436
438
  except ImportError:
437
439
  pass
squad/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '1.90'
1
+ __version__ = '1.92'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: squad
3
- Version: 1.90
3
+ Version: 1.92
4
4
  Summary: Software Quality Dashboard
5
5
  Home-page: https://github.com/Linaro/squad
6
6
  Author: Antonio Terceiro
@@ -40,7 +40,7 @@ Requires-Dist: sqlparse
40
40
  Requires-Dist: svgwrite
41
41
  Requires-Dist: whitenoise
42
42
  Provides-Extra: postgres
43
- Requires-Dist: psycopg2; extra == "postgres"
43
+ Requires-Dist: psycopg2-binary; extra == "postgres"
44
44
 
45
45
  Software Quality Dashboard
46
46
 
@@ -7,18 +7,19 @@ 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=nx_cXfFOf3i5z7bmIzwkRhBgVHWtDBfK40-yo5hQUzw,14663
10
+ squad/settings.py,sha256=0MZ48SV_7CTrLMik2ubWf8-ROQiFju6CKnUC3iR8KAc,14800
11
11
  squad/socialaccount.py,sha256=vySqPwQ3qVVpahuJ-Snln8K--yzRL3bw4Nx27AsB39A,789
12
12
  squad/urls.py,sha256=JiEfVW8YlzLPE52c2aHzdn5kVVKK4o22w8h5KOA6QhQ,2776
13
- squad/version.py,sha256=xCyEItfDbvgP8ttkgjhTpQfmnJCsuxMtkuIMOjALn54,21
13
+ squad/version.py,sha256=WHUX3wrk23jPrWzNUft2dot0QtSqj7kO0c3Q3yKJiDM,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
17
- squad/api/ci.py,sha256=ymG-eMKXpJgrVUiZcqJW-dYZQKvm1LkdR3TUMe4OSoM,6943
17
+ squad/api/ci.py,sha256=QjGIhSpm8gmIjH4Nd2NAWtJItSVleg3QOLxBU_p9h1E,7082
18
18
  squad/api/data.py,sha256=obKDV0-neEvj5lPF9VED2gy_hpfhGtLJABYvSY38ing,2379
19
19
  squad/api/filters.py,sha256=Zvp8DCJmiNquFWqvfVseEAAMYYPiT95RUjqKdzcqSnw,6917
20
+ squad/api/prometheus.py,sha256=MEzSZtYYx6PXreIwZzcVHLp-1vVQ9IKhi9hb8b0vjUk,1839
20
21
  squad/api/rest.py,sha256=ZtbK0c1BLPPnsX79XlKFVYONM_VJ0vacWZ2JsdCd4l0,77342
21
- squad/api/urls.py,sha256=rmsdaL1uOCVSZ5x1redup9RliICmijaBjRK5ObsTkG8,1343
22
+ squad/api/urls.py,sha256=c-o27_RP0ynOtxuyRKUl274fFMWWrzoii31Mr2saxSQ,1414
22
23
  squad/api/utils.py,sha256=Sa8QFId3_oSqD2UOoY3Kuh54LLDLPNMq2sub5ktd6Fs,1160
23
24
  squad/api/views.py,sha256=WH4c10e7iRmuL5tWDxG4zEFHzvF5hxDpEVvybfvbc_E,3880
24
25
  squad/ci/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -29,10 +30,10 @@ squad/ci/models.py,sha256=Fm-4b3SDgMh9HXzqjOd4iZDRMJ1D9AnZ2cg7i2OR248,16018
29
30
  squad/ci/tasks.py,sha256=P0NYjLuyUViTpO1jZMuRVREbFDCccrMCZDw5E4pt928,3882
30
31
  squad/ci/utils.py,sha256=38zHpw8xkZDSFlkG-2BwSK6AkcddK9OkN9LXuQ3SHR0,97
31
32
  squad/ci/backend/__init__.py,sha256=yhpotXT9F4IdAOXvGQ3-17eOHAFwoaqf9SnMX17ab30,534
32
- squad/ci/backend/fake.py,sha256=9sPKndsGd5GDNPp35v-zfJWXZCbge-yXH3RBQGgTlPk,2340
33
- squad/ci/backend/lava.py,sha256=E4QE0XtAiqArzzx3YSv7_2qYUBs4aSw8JOz0AV0z9W8,33877
34
- squad/ci/backend/null.py,sha256=0CVylWELIZw3JyzCROB4XXAjgQUi15YjQz5caRfTNBo,5434
35
- squad/ci/backend/tuxsuite.py,sha256=-A4p5HpUWnIC-61os0vdJOfAGoO81szoLkSgzyaUt6c,17901
33
+ squad/ci/backend/fake.py,sha256=7Rl-JXnBYThDomOBzBsN9XuVkSjSHTZjtZOURdowZbA,2397
34
+ squad/ci/backend/lava.py,sha256=WeOJJNxv42geGf3Y6r-I0WnhWinxpSSgZAFAwfkiXGY,34039
35
+ squad/ci/backend/null.py,sha256=htEd4NbrXLKdPgFfTS0Ixm8PdT6Ghat3BCYi2zjfuv0,5624
36
+ squad/ci/backend/tuxsuite.py,sha256=dTQNgHs5HNrY2LUaSH6jXiBLVjgyMNTqJ6CUWU3yPK4,18914
36
37
  squad/ci/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
38
  squad/ci/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
39
  squad/ci/management/commands/create_tuxsuite_boot_tests.py,sha256=JvjNusebLX71eyz9d-kaeCyekYSpzc1eXoeIqWK9ygo,4045
@@ -305,7 +306,7 @@ squad/frontend/project_settings.py,sha256=TtWz8h8Goeb3pccLy9jLUibeHqyqkdK8phL7_V
305
306
  squad/frontend/queries.py,sha256=NxQF2woAf9A4Wk_ozHzZXOGmr2as-j7hqfvmsfJ-ojc,967
306
307
  squad/frontend/setup.py,sha256=NF9VunY1HJGB2HsHJss-go7EGmqr__JASddxiBCvmeQ,169
307
308
  squad/frontend/tests.py,sha256=PidrjaToK_Cks0s9Mc4i3Vh4UXOWoXTZlpnxQ2wWjHY,8740
308
- squad/frontend/urls.py,sha256=biWauxwXR5j9kOfrSUqkv1Iqz-elB2aNViS9_UFoLzQ,4882
309
+ squad/frontend/urls.py,sha256=-rxbsUlMyxldzoVKiVAOMAREqU8SOipy4CqBTlULuMQ,5055
309
310
  squad/frontend/user_settings.py,sha256=U_i59iuylg98uH98K4ezPa2NY56idslBhn7MS6FguHQ,4976
310
311
  squad/frontend/utils.py,sha256=DeH58CJUI1dovpQrj3a-DcxNzM0cxsnBDOF0mrC4Qws,1364
311
312
  squad/frontend/views.py,sha256=4ld9n8pOS35sUKPifgCY4rLHL_Dmybfo_Jg0_Bo5sxs,27031
@@ -387,7 +388,7 @@ squad/frontend/templates/squad/knownissues.jinja2,sha256=RdQZ2AKgV97953eIuP-4IwN
387
388
  squad/frontend/templates/squad/login.jinja2,sha256=NPp20MpmgoGxWOschCUxcZMJKdnkVhUmy8kpCgogPs0,2775
388
389
  squad/frontend/templates/squad/metrics.jinja2,sha256=7oFBkTiGi3k1UtfR5x0RS961u6rsRCe_YcEXklA0iLA,3277
389
390
  squad/frontend/templates/squad/project-nav.jinja2,sha256=AHN7r5TMvJ-NwEo_u3vlJg34J1njsuII32SgQuTfiwA,1526
390
- squad/frontend/templates/squad/project.jinja2,sha256=JUmiYPlAo5hlUd-M32QmyjWmqe49NILySVFQ2a39Ftc,737
391
+ squad/frontend/templates/squad/project.jinja2,sha256=k2orc5C6Fxp_74utQAN1sa6XPOFMF2sC2D2y671pgSg,887
391
392
  squad/frontend/templates/squad/test_history.jinja2,sha256=g_pHD4yQdfXK1D8-tTAPG4yzoqbDVUYm6ml2hANffp8,5869
392
393
  squad/frontend/templates/squad/test_run.jinja2,sha256=smxFEC7XnHu28Wj7iC2WQrGjpuPiqsxASpflbyYGG_A,1176
393
394
  squad/frontend/templates/squad/test_run_suite_metrics.jinja2,sha256=WGjlObw7ZTGoomTmON0O2QRHHdmEBOYf9xMSTWP83F4,1780
@@ -425,17 +426,17 @@ squad/plugins/__init__.py,sha256=9BSzy2jFIoDpWlhD7odPPrLdW4CC3btBhdFCvB651dM,152
425
426
  squad/plugins/example.py,sha256=BKpwd315lHRIuNXJPteibpwfnI6C5eXYHYdFYBtVmsI,89
426
427
  squad/plugins/gerrit.py,sha256=CqO2KnFQzu9utr_TQ-sGr1wg3ln0B-bS2-c0_i8T5-c,7009
427
428
  squad/plugins/github.py,sha256=pdtLZw_7xNuzkaFvY_zWi0f2rsMlalXjKm7sz0eADz4,2429
428
- squad/plugins/linux_log_parser.py,sha256=9vjt3z7ZDYofR90-JZv260phKMJyRv3sdksr8satgi0,2662
429
+ squad/plugins/linux_log_parser.py,sha256=MB8ScFZycq70Rrm7IM_Cw95rMtqVS9w4RhS5HhBSpcE,3292
429
430
  squad/plugins/lib/__init__.py,sha256=jzazbAvp2_ibblAs0cKZrmo9aR2EL3hKLyRDE008r2I,40
430
- squad/plugins/lib/base_log_parser.py,sha256=lfGoHWYTzOmWxME-qGArpJatzjUdy0uEII5eokDfP1Y,6189
431
+ squad/plugins/lib/base_log_parser.py,sha256=OW6JkZ3PM5RiDkt9UZ7OFFpUIArCxFUaqovynzwBL1Y,6573
431
432
  squad/run/__init__.py,sha256=ssE8GPAGFiK6V0WpZYowav6Zqsd63dfDMMYasNa1sQg,1410
432
433
  squad/run/__main__.py,sha256=DOl8JOi4Yg7DdtwnUeGqtYBJ6P2k-D2psAEuYOjWr8w,66
433
434
  squad/run/listener.py,sha256=jBeOQhPGb4EdIREB1QsCzYuumsfJ-TqJPd3nR-0m59g,200
434
435
  squad/run/scheduler.py,sha256=CDJG3q5C0GuQuxwlMOfWTSSJpDdwbR6rzpbJfuA0xuw,277
435
436
  squad/run/worker.py,sha256=jtML0h5qKDuSbpJ6_rpWP4MT_rsGA7a24AhwGxBquzk,594
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,,
437
+ squad-1.92.dist-info/COPYING,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
438
+ squad-1.92.dist-info/METADATA,sha256=_lF0F4lPQq88zJhPQ7M38zYoiWXjPWDKCOXr10WTKfg,1278
439
+ squad-1.92.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
440
+ squad-1.92.dist-info/entry_points.txt,sha256=J_jG3qnkoOHX4RFNGC0f83eJ4BSvK3pqLFkoF3HWfmA,195
441
+ squad-1.92.dist-info/top_level.txt,sha256=_x9uqE1XppiiytmVTl_qNgpnXus6Gsef69HqfliE7WI,6
442
+ squad-1.92.dist-info/RECORD,,
File without changes
File without changes