| |
@@ -19,19 +19,18 @@
|
| |
|
| |
"""ORM class for bug information stored in the database"""
|
| |
|
| |
- import datetime
|
| |
+ from datetime import datetime
|
| |
import json
|
| |
- from typing import Any, Optional
|
| |
+ from typing import Any, Optional, List
|
| |
|
| |
from sqlalchemy import or_
|
| |
from sqlalchemy.ext.hybrid import hybrid_property
|
| |
|
| |
- from blockerbugs import db, BaseModel, models
|
| |
+ from blockerbugs import db, models
|
| |
import blockerbugs.models.milestone as model_milestone
|
| |
- import blockerbugs.models.update as model_update
|
| |
|
| |
|
| |
- class Bug(BaseModel):
|
| |
+ class Bug(db.Model):
|
| |
"""A representation of a Bugzilla ticket, with some additional attributes.
|
| |
|
| |
Note: While a particular bug (with a given `bugid`) can exist only once in Bugzilla, a matching
|
| |
@@ -39,37 +38,49 @@
|
| |
`Milestone`. So e.g. there can only be a single `Bug` with `bugid=123456` under F35-Beta, but
|
| |
there can be another `Bug` with `bugid=123456` under F35-Final, or F36-Beta.
|
| |
"""
|
| |
+ __tablename__ = "bug"
|
| |
|
| |
- id = db.Column(db.Integer, primary_key=True)
|
| |
- bugid = db.Column(db.Integer, unique=False)
|
| |
+ id: db.Mapped[int] = db.mapped_column(primary_key=True)
|
| |
+ bugid: db.Mapped[Optional[int]]
|
| |
"""The bug number, e.g. 123456"""
|
| |
- url = db.Column(db.String(1024), unique=False)
|
| |
- summary = db.Column(db.String(2048), unique=False)
|
| |
- status = db.Column(db.String(80), unique=False)
|
| |
+ url: db.Mapped[Optional[str]] = db.mapped_column(db.String(1024))
|
| |
+ summary: db.Mapped[Optional[str]] = db.mapped_column(db.String(2048))
|
| |
+ status: db.Mapped[Optional[str]] = db.mapped_column(db.String(80))
|
| |
"""E.g. 'NEW' or 'ASSIGNED'"""
|
| |
- component = db.Column(db.String(80), unique=False)
|
| |
- active = db.Column(db.Boolean(create_constraint=True, name='active_bool'))
|
| |
+ component: db.Mapped[Optional[str]] = db.mapped_column(db.String(80))
|
| |
+ active: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='active_bool'))
|
| |
"""An alias for 'open', i.e. `True` when open, `False` when closed"""
|
| |
- last_bug_sync = db.Column(db.DateTime)
|
| |
- needinfo = db.Column(db.Boolean(create_constraint=True, name='needinfo_bool'))
|
| |
- needinfo_requestee = db.Column(db.String(1024), unique=False)
|
| |
- last_whiteboard_change = db.Column(db.DateTime)
|
| |
+ last_bug_sync: db.Mapped[Optional[datetime]]
|
| |
+ needinfo: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='needinfo_bool'))
|
| |
+ needinfo_requestee: db.Mapped[Optional[str]] = db.mapped_column(db.String(1024))
|
| |
+ last_whiteboard_change: db.Mapped[Optional[datetime]]
|
| |
"""The time when we detected a blocker/FE keyword change. It doesn't really mark *any*
|
| |
whiteboard change, just for those tracked keywords."""
|
| |
- proposed_blocker = db.Column(db.Boolean(create_constraint=True, name='proposed_blocker_bool'))
|
| |
- proposed_fe = db.Column(db.Boolean(create_constraint=True, name='proposed_fe_bool'))
|
| |
- rejected_blocker = db.Column(db.Boolean(create_constraint=True, name='rejected_blocker_bool'))
|
| |
- rejected_fe = db.Column(db.Boolean(create_constraint=True, name='rejected_fe_bool'))
|
| |
- accepted_blocker = db.Column(db.Boolean(create_constraint=True, name='accepted_blocker_bool'))
|
| |
- accepted_0day = db.Column(db.Boolean(create_constraint=True, name='accepted_0day_bool'))
|
| |
- accepted_prevrel = db.Column(db.Boolean(create_constraint=True, name='accepted_prevrel_bool'))
|
| |
- accepted_fe = db.Column(db.Boolean(create_constraint=True, name='accepted_fe_bool'))
|
| |
- prioritized = db.Column(db.Boolean(create_constraint=True, name='prioritized_bool'))
|
| |
- milestone_id = db.Column(db.Integer, db.ForeignKey('milestone.id'))
|
| |
- milestone: Optional['model_milestone.Milestone'] = db.relationship(
|
| |
- 'Milestone', back_populates='bugs', cascade_backrefs=False)
|
| |
- discussion_link = db.Column(db.String, unique=False)
|
| |
- votes: str = db.Column(db.Text, default='{}', nullable=False)
|
| |
+ proposed_blocker: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='proposed_blocker_bool'))
|
| |
+ proposed_fe: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='proposed_fe_bool'))
|
| |
+ rejected_blocker: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='rejected_blocker_bool'))
|
| |
+ rejected_fe: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='rejected_fe_bool'))
|
| |
+ accepted_blocker: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='accepted_blocker_bool'))
|
| |
+ accepted_0day: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='accepted_0day_bool'))
|
| |
+ accepted_prevrel: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='accepted_prevrel_bool'))
|
| |
+ accepted_fe: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='accepted_fe_bool'))
|
| |
+ prioritized: db.Mapped[Optional[bool]] = db.mapped_column(
|
| |
+ db.Boolean(create_constraint=True, name='prioritized_bool'))
|
| |
+ milestone_id: db.Mapped[Optional[int]] = db.mapped_column(db.ForeignKey('milestone.id'))
|
| |
+ milestone: db.Mapped[Optional['Milestone']] = db.relationship( # noqa: F821
|
| |
+ back_populates='bugs', cascade_backrefs=False)
|
| |
+ discussion_link: db.Mapped[Optional[str]]
|
| |
+ votes: db.Mapped[str] = db.mapped_column(db.Text, default='{}')
|
| |
"""A JSON representation of dict of all BugVoteTrackers and corresponding output of
|
| |
`BugVoteTracker.enumerate_votes()` with comment ids removed:
|
| |
```
|
| |
@@ -78,12 +89,11 @@
|
| |
"+1": ["nick3"]}
|
| |
}
|
| |
```"""
|
| |
- _depends_on: str = db.Column('depends_on', db.Text, default='[]', nullable=False)
|
| |
+ _depends_on: db.Mapped[str] = db.mapped_column('depends_on', db.Text, default='[]')
|
| |
"""A JSON list of bug numbers which this bug depends on"""
|
| |
- updates: list['model_update.Update'] = db.relationship(
|
| |
- 'Update', secondary=models.update_fixes, back_populates='bugs', lazy='dynamic',
|
| |
- order_by=('[Update.status.desc(), Update.request.desc()]'), cascade_backrefs=False
|
| |
- )
|
| |
+ updates: db.Mapped[List['Update']] = db.relationship( # noqa: F821
|
| |
+ secondary=models.update_fixes, back_populates='bugs', lazy='dynamic',
|
| |
+ order_by='[Update.status.desc(), Update.request.desc()]', cascade_backrefs=False)
|
| |
|
| |
def __init__(self,
|
| |
bugid: Optional[int],
|
| |
@@ -95,8 +105,8 @@
|
| |
active: Optional[bool],
|
| |
needinfo: Optional[bool],
|
| |
needinfo_requestee: Optional[str],
|
| |
- last_whiteboard_change: Optional[datetime.datetime] = datetime.datetime.utcnow(),
|
| |
- last_bug_sync: Optional[datetime.datetime] = datetime.datetime.now(),
|
| |
+ last_whiteboard_change: Optional[datetime] = datetime.utcnow(),
|
| |
+ last_bug_sync: Optional[datetime] = datetime.now(),
|
| |
depends_on: Optional[list[int]] = None) -> None:
|
| |
self.bugid = bugid
|
| |
self.url = url
|
| |
@@ -144,18 +154,18 @@
|
| |
self.prioritized)
|
| |
|
| |
@is_proposed_accepted.expression # type: ignore[no-redef]
|
| |
- def is_proposed_accepted(cls) -> bool:
|
| |
+ def is_proposed_accepted(self) -> bool:
|
| |
"""Return ``True`` if this bug is either proposed or accepted as a Blocker, FreezeException
|
| |
or Prioritized.
|
| |
"""
|
| |
# The SQLAlchemy expression when using ``is_proposed_accepted`` in a query.
|
| |
- return or_(cls.proposed_blocker,
|
| |
- cls.proposed_fe,
|
| |
- cls.accepted_blocker,
|
| |
- cls.accepted_0day,
|
| |
- cls.accepted_prevrel,
|
| |
- cls.accepted_fe,
|
| |
- cls.prioritized)
|
| |
+ return or_(self.proposed_blocker,
|
| |
+ self.proposed_fe,
|
| |
+ self.accepted_blocker,
|
| |
+ self.accepted_0day,
|
| |
+ self.accepted_prevrel,
|
| |
+ self.accepted_fe,
|
| |
+ self.prioritized)
|
| |
|
| |
def __repr__(self):
|
| |
return '<bug %d: %s>' % (self.bugid, self.summary)
|
| |
@@ -178,7 +188,7 @@
|
| |
if self.proposed_blocker != buginfo['proposed'] or \
|
| |
self.accepted_blocker != buginfo['accepted'] or \
|
| |
self.rejected_blocker != buginfo['rejected']:
|
| |
- self.last_whiteboard_change = datetime.datetime.utcnow()
|
| |
+ self.last_whiteboard_change = datetime.utcnow()
|
| |
self.proposed_blocker = buginfo['proposed']
|
| |
self.accepted_0day = buginfo['0day']
|
| |
self.accepted_prevrel = buginfo['prevrel']
|
| |
@@ -188,7 +198,7 @@
|
| |
if self.proposed_fe != buginfo['proposed'] or \
|
| |
self.accepted_fe != buginfo['accepted'] or \
|
| |
self.rejected_fe != buginfo['rejected']:
|
| |
- self.last_whiteboard_change = datetime.datetime.utcnow()
|
| |
+ self.last_whiteboard_change = datetime.utcnow()
|
| |
self.proposed_fe = buginfo['proposed']
|
| |
self.accepted_fe = buginfo['accepted']
|
| |
self.rejected_fe = buginfo['rejected']
|
| |
Please review per commit for better readability. Note that manual adjustments in your dev env are needed in order to test it locally, see the description of one of the commits. Thanks.
@frantisekz This will require a config change when deploying it.
Fixes: #266