Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion EC2Reporter/tests/test_EC2Reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_ec2reporter_report(mock_expanduser, live_server, tmp_path, fm_user):

reporter.report(None)
host = Instance.objects.get(pk=host.pk) # re-read
assert host.status_data is None
assert not host.status_data

reporter = EC2Reporter(
sigCacheDir=str(sigcache_path),
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ select = [
"B",
# flake8-comprehensions
"C4",
# flake8-django
"DJ",
# pycodestyle
"E",
# Pyflakes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.27 on 2026-05-12 19:13

from django.db import migrations, models


def null_to_empty(apps, schema_editor):
ReportSummary = apps.get_model("covmanager", "ReportSummary")
ReportSummary.objects.filter(cached_result__isnull=True).update(cached_result="")


class Migration(migrations.Migration):

dependencies = [
('covmanager', '0007_report_tag'),
]

operations = [
migrations.RunPython(null_to_empty, reverse_code=migrations.RunPython.noop),
migrations.AlterField(
model_name='reportsummary',
name='cached_result',
field=models.TextField(blank=True),
),
]
20 changes: 19 additions & 1 deletion server/covmanager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class Repository(models.Model):
name = models.CharField(max_length=255, blank=False)
location = models.CharField(max_length=1023, blank=False)

def __str__(self):
return self.name

def getInstance(self):
# Dynamically instantiate the provider as requested
providerModule = __import__(
Expand All @@ -38,6 +41,9 @@ class CollectionFile(models.Model):
)
format = models.IntegerField(default=0)

def __str__(self):
return self.file.name


class Collection(models.Model):
created = models.DateTimeField(default=timezone.now)
Expand All @@ -51,6 +57,9 @@ class Collection(models.Model):
CollectionFile, blank=True, null=True, on_delete=models.deletion.CASCADE
)

def __str__(self):
return self.description or f"Collection #{self.pk}"

def __init__(self, *args, **kwargs):
# This variable can hold the deserialized contents of the coverage blob
self.content = None
Expand Down Expand Up @@ -208,6 +217,9 @@ class ReportConfiguration(models.Model):
"self", blank=True, null=True, on_delete=models.deletion.CASCADE
)

def __str__(self):
return self.description or f"ReportConfiguration #{self.pk}"

def apply(self, collection):
CoverageHelper.apply_include_exclude_directives(
collection, self.directives.splitlines()
Expand All @@ -217,7 +229,10 @@ def apply(self, collection):

class ReportSummary(models.Model):
collection = models.OneToOneField(Collection, on_delete=models.deletion.CASCADE)
cached_result = models.TextField(null=True, blank=True)
cached_result = models.TextField(blank=True)

def __str__(self):
return f"ReportSummary #{self.pk}"


class Report(models.Model):
Expand All @@ -235,3 +250,6 @@ class Report(models.Model):
is_monthly = models.BooleanField(blank=False, default=False)
is_quarterly = models.BooleanField(blank=False, default=False)
tag = models.CharField(max_length=64, blank=True)

def __str__(self):
return f"Report #{self.pk}"
6 changes: 3 additions & 3 deletions server/covmanager/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ def check_notify_coverage_drops(current_pk, previous_pk, retries=20):
previous = Collection.objects.get(pk=previous_pk)

if (
current.reportsummary.cached_result is None
or previous.reportsummary.cached_result is None
not current.reportsummary.cached_result
or not previous.reportsummary.cached_result
):
if retries:
# try again in 60s
Expand Down Expand Up @@ -155,7 +155,7 @@ def identify_coverage_drops(revision, ipc_only=False):

for collection in collections:
if not hasattr(collection, "reportsummary"):
summary = ReportSummary(collection=collection, cached_result=None)
summary = ReportSummary(collection=collection, cached_result="")
summary.save()
calculate_report_summary.delay(summary.pk)

Expand Down
4 changes: 2 additions & 2 deletions server/covmanager/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ def collections_reportsummary_api(request, collectionid):
task_scheduled = False

if not hasattr(collection, "reportsummary"):
summary = ReportSummary(collection=collection, cached_result=None)
summary = ReportSummary(collection=collection, cached_result="")
summary.save()
calculate_report_summary.delay(summary.pk)
task_scheduled = True
Expand All @@ -483,7 +483,7 @@ def collections_reportsummary_api(request, collectionid):
if request.method == "POST":
# This is a refresh request
if not task_scheduled:
summary.cached_result = None
summary.cached_result = ""
summary.save()
calculate_report_summary.delay(summary.pk)
return HttpResponse(content=json.dumps({"msg": "Success"}))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Generated by Django 4.2.27 on 2026-05-12 19:13

from django.db import migrations, models


def null_to_empty(apps, schema_editor):
Bucket = apps.get_model("crashmanager", "Bucket")
Bucket.objects.filter(optimizedSignature__isnull=True).update(optimizedSignature="")

CrashEntry = apps.get_model("crashmanager", "CrashEntry")
CrashEntry.objects.filter(cachedCrashInfo__isnull=True).update(cachedCrashInfo="")

# Product and OS have a unique constraint on (name, version). Multiple rows with
# version=NULL are distinct in SQL (NULL != NULL), but would collide after converting
# to ''. Deduplicate by keeping the lowest-pk row per name and re-pointing any
# CrashEntry FK references before deleting the extras.
for model_name, fk_field in [("Product", "product"), ("OS", "os")]:
Model = apps.get_model("crashmanager", model_name)
canonical = {}
for obj in Model.objects.filter(version__isnull=True).order_by("pk"):
if obj.name in canonical:
CrashEntry.objects.filter(
**{f"{fk_field}_id": obj.pk}
).update(**{f"{fk_field}_id": canonical[obj.name]})
obj.delete()
else:
canonical[obj.name] = obj.pk
Model.objects.filter(version__isnull=True).update(version="")


class Migration(migrations.Migration):

dependencies = [
('crashmanager', '0019_alter_user_options'),
]

operations = [
migrations.RunPython(null_to_empty, reverse_code=migrations.RunPython.noop),
migrations.AlterField(
model_name='bucket',
name='optimizedSignature',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='crashentry',
name='cachedCrashInfo',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='os',
name='version',
field=models.CharField(blank=True, max_length=127),
),
migrations.AlterField(
model_name='product',
name='version',
field=models.CharField(blank=True, max_length=127),
),
]
Loading
Loading