mirror of
https://github.com/bugsink/bugsink.git
synced 2026-01-06 05:10:15 -06:00
86 lines
3.9 KiB
Python
86 lines
3.9 KiB
Python
from releases.models import ordered_releases
|
|
|
|
# note that we don't check for is_muted anywhere in this file; this is because issues that are muted are unresolved (the
|
|
# combination of muted & resolved is illegal and we enforce this elsewhere) and the unresolved case is trivially not a
|
|
# regression. (first guard clause in `issue_is_regression`)
|
|
|
|
|
|
def is_regression(sorted_releases, fixed_at, events_at, current_event_at):
|
|
# NOTE: linear in time with the number of releases; however, for now it's a nice reference implementation.
|
|
# premature optimizations and the root of all evil and all that. some thoughts though:
|
|
#
|
|
# "if current_event_at in events_at" return False <= this could be a shortcut
|
|
# * sorted_releases grows with time for projects, but how many 'fixed_at` can we reasonably expect?
|
|
# unless we even do things like release cleanup, which isn't so crazy...
|
|
# * we need not consider anything (from sorted_releases) before the first `fixed_at` moment, because that's the
|
|
# first flipping of `marked_as_resolved`. this could even be done at the DB level.
|
|
#
|
|
marked_as_resolved = False
|
|
|
|
for r in sorted_releases:
|
|
if r in events_at:
|
|
marked_as_resolved = False
|
|
elif r in fixed_at:
|
|
marked_as_resolved = True
|
|
|
|
if current_event_at == r:
|
|
return marked_as_resolved
|
|
|
|
raise Exception("Can't find release '%s'" % current_event_at)
|
|
|
|
|
|
def issue_is_regression(issue, current_event_at):
|
|
"""
|
|
Given that a new event has just occurred, is this issue a regression?
|
|
`current_event_at` is the release at which the event occurred.
|
|
|
|
Must be called after `is_resolved_by_next_release`-handling for new releases (i.e. `create_release_if_needed`) to
|
|
ensure the logic surrounding `issue.is_resolved_by_next_release` is correct.
|
|
"""
|
|
|
|
if not issue.is_resolved:
|
|
# unresolved issues can't be regressions by definition
|
|
return False
|
|
|
|
if issue.is_resolved_by_next_release:
|
|
# if issue.is_resolved and issue.is_resolved_by_next_release <= implied because of the first guard clause.
|
|
# Which is to say the `is_resolved` marker is there, but another field qualifies it as "only in the future".
|
|
# Which means that seeing new events does not imply a regression, because that future hasn't arrived yet.
|
|
return False
|
|
|
|
if not issue.project.has_releases:
|
|
# the simple case: no releases means that seeing new events implies a regression if the issue.is_resolved, which
|
|
# is True given the first guard clause.
|
|
return True
|
|
|
|
sorted_releases = [r.version for r in ordered_releases(project=issue.project)]
|
|
fixed_at = issue.get_fixed_at()
|
|
events_at = issue.get_events_at()
|
|
|
|
return is_regression(sorted_releases, fixed_at, events_at, current_event_at)
|
|
|
|
|
|
def is_regression_2(sorted_releases, fixed_at, events_at, current_event_at):
|
|
# AKA is_regression_with_fixed_later_info, i.e. returns a tuple of which the second element expresses something
|
|
# about this happening in the middle of your timeline. On a second viewing I'm a lot less sure that this is useful
|
|
# than I was previously. I mean: if you marked something as fixed (explicitly) on some old feature branch, and it
|
|
# reoccurs, you want to know that. The fact that you've also marked it as fixed on a later branch doesn't change
|
|
# that.
|
|
|
|
# for lack of a better name; I want to express this idea somewhere first; let's see how we utilize it in actual code
|
|
# later; hence also copy/pasta
|
|
fixed_at = fixed_at[:]
|
|
marked_as_resolved = False
|
|
|
|
for r in sorted_releases:
|
|
if r in events_at:
|
|
marked_as_resolved = False
|
|
elif r in fixed_at:
|
|
marked_as_resolved = True
|
|
fixed_at.remove(r)
|
|
|
|
if current_event_at == r:
|
|
return marked_as_resolved, len(fixed_at) > 0
|
|
|
|
raise Exception("Can't find release '%s'" % current_event_at)
|