mirror of
https://github.com/bugsink/bugsink.git
synced 2025-12-21 13:00:13 -06:00
detection of a new release through an event ⇏ triggering of a TurningPoint
This more exactly expresses semantics by itself, and is also in preparation of creating releases through the API (which have no triggering event) See #146
This commit is contained in:
@@ -369,7 +369,7 @@ class BaseIngestAPIView(View):
|
||||
# multiple events with the same event_id "don't happen" (i.e. are the result of badly misbehaving clients)
|
||||
raise ValidationError("Event already exists", code="event_already_exists")
|
||||
|
||||
release = create_release_if_needed(project, event.release, event, issue)
|
||||
release = create_release_if_needed(project, event.release, event.ingested_at, issue)
|
||||
|
||||
if issue_created:
|
||||
TurningPoint.objects.create(
|
||||
|
||||
@@ -193,7 +193,8 @@ class RegressionIssueTestCase(DjangoTestCase):
|
||||
|
||||
def test_issue_is_regression_no_releases(self):
|
||||
project = Project.objects.create()
|
||||
create_release_if_needed(fresh(project), "", create_event(project))
|
||||
timestamp = datetime(2020, 1, 1, tzinfo=timezone.utc)
|
||||
create_release_if_needed(fresh(project), "", timestamp)
|
||||
|
||||
# new issue is not a regression
|
||||
issue = Issue.objects.create(project=project, **denormalized_issue_fields())
|
||||
@@ -212,7 +213,8 @@ class RegressionIssueTestCase(DjangoTestCase):
|
||||
|
||||
def test_issue_had_no_releases_but_now_does(self):
|
||||
project = Project.objects.create()
|
||||
create_release_if_needed(fresh(project), "", create_event(project))
|
||||
timestamp = datetime(2020, 1, 1, tzinfo=timezone.utc)
|
||||
create_release_if_needed(fresh(project), "", timestamp)
|
||||
|
||||
# new issue is not a regression
|
||||
issue = Issue.objects.create(project=project, **denormalized_issue_fields())
|
||||
@@ -223,15 +225,16 @@ class RegressionIssueTestCase(DjangoTestCase):
|
||||
issue.save()
|
||||
|
||||
# a new release happens
|
||||
create_release_if_needed(fresh(project), "1.0.0", create_event(project))
|
||||
create_release_if_needed(fresh(project), "1.0.0", timestamp)
|
||||
|
||||
self.assertTrue(issue_is_regression(fresh(issue), "1.0.0"))
|
||||
|
||||
def test_issue_is_regression_with_releases_resolve_by_latest(self):
|
||||
project = Project.objects.create()
|
||||
timestamp = datetime(2020, 1, 1, tzinfo=timezone.utc)
|
||||
|
||||
create_release_if_needed(fresh(project), "1.0.0", create_event(project))
|
||||
create_release_if_needed(fresh(project), "2.0.0", create_event(project))
|
||||
create_release_if_needed(fresh(project), "1.0.0", timestamp)
|
||||
create_release_if_needed(fresh(project), "2.0.0", timestamp)
|
||||
|
||||
# new issue is not a regression
|
||||
issue = Issue.objects.create(project=project, **denormalized_issue_fields())
|
||||
@@ -244,7 +247,7 @@ class RegressionIssueTestCase(DjangoTestCase):
|
||||
self.assertTrue(issue_is_regression(fresh(issue), "2.0.0"))
|
||||
|
||||
# a new release happens, and the issue is seen there: also a regression
|
||||
create_release_if_needed(fresh(project), "3.0.0", create_event(project))
|
||||
create_release_if_needed(fresh(project), "3.0.0", timestamp)
|
||||
self.assertTrue(issue_is_regression(fresh(issue), "3.0.0"))
|
||||
|
||||
# reopen the issue (as is done when a real regression is seen; or as would be done manually); nothing is a
|
||||
@@ -256,9 +259,10 @@ class RegressionIssueTestCase(DjangoTestCase):
|
||||
|
||||
def test_issue_is_regression_with_releases_resolve_by_next(self):
|
||||
project = Project.objects.create()
|
||||
timestamp = datetime(2020, 1, 1, tzinfo=timezone.utc)
|
||||
|
||||
create_release_if_needed(fresh(project), "1.0.0", create_event(project))
|
||||
create_release_if_needed(fresh(project), "2.0.0", create_event(project))
|
||||
create_release_if_needed(fresh(project), "1.0.0", timestamp)
|
||||
create_release_if_needed(fresh(project), "2.0.0", timestamp)
|
||||
|
||||
# new issue is not a regression
|
||||
issue = Issue.objects.create(project=project, **denormalized_issue_fields())
|
||||
@@ -271,11 +275,11 @@ class RegressionIssueTestCase(DjangoTestCase):
|
||||
self.assertFalse(issue_is_regression(fresh(issue), "2.0.0"))
|
||||
|
||||
# a new release appears (as part of a new event); this is a regression
|
||||
create_release_if_needed(fresh(project), "3.0.0", create_event(project))
|
||||
create_release_if_needed(fresh(project), "3.0.0", timestamp)
|
||||
self.assertTrue(issue_is_regression(fresh(issue), "3.0.0"))
|
||||
|
||||
# first-seen at any later release: regression
|
||||
create_release_if_needed(fresh(project), "4.0.0", create_event(project))
|
||||
create_release_if_needed(fresh(project), "4.0.0", timestamp)
|
||||
self.assertTrue(issue_is_regression(fresh(issue), "4.0.0"))
|
||||
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ class Release(models.Model):
|
||||
return self.version[:12]
|
||||
|
||||
|
||||
def create_release_if_needed(project, version, event, issue=None):
|
||||
def create_release_if_needed(project, version, timestamp, issue=None):
|
||||
if version is None:
|
||||
# because `create_release_if_needed` is called with Issue.release (non-nullable), the below "won't happen"
|
||||
raise ValueError('The None-like version must be the empty string')
|
||||
@@ -119,16 +119,14 @@ def create_release_if_needed(project, version, event, issue=None):
|
||||
if release == project.get_latest_release():
|
||||
resolved_by_next_qs = Issue.objects.filter(project=project, is_resolved_by_next_release=True)
|
||||
|
||||
# NOTE: once we introduce an explicit way of creating releases (not event-based) we can not rely on a
|
||||
# triggering event anymore for our timestamp.
|
||||
|
||||
TurningPoint.objects.bulk_create([TurningPoint(
|
||||
project=project,
|
||||
issue=issue, kind=TurningPointKind.NEXT_MATERIALIZED, triggering_event=event,
|
||||
metadata=json.dumps({"actual_release": release.version}), timestamp=event.ingested_at)
|
||||
issue=issue, kind=TurningPointKind.NEXT_MATERIALIZED,
|
||||
# the detection of a new release through an event does not imply a triggering of a TurningPoint:
|
||||
triggering_event=None,
|
||||
metadata=json.dumps({"actual_release": release.version}), timestamp=timestamp)
|
||||
for issue in resolved_by_next_qs
|
||||
])
|
||||
event.never_evict = True # .save() will be called by the caller of this function
|
||||
|
||||
resolved_by_next_qs.update(
|
||||
fixed_at=Concat("fixed_at", Value(release.version + "\n")),
|
||||
|
||||
Reference in New Issue
Block a user