BugzillaORM — различия между версиями
м (→Обновление модели) |
|||
(не показано 66 промежуточных версий этого же участника) | |||
Строка 1: | Строка 1: | ||
− | + | [[Категория:Разработка]] | |
+ | В Bugzilla половина кода в шаблонах, половина на основе полу-ORM’а Bugzilla::Object. Большая часть — говнокод. С одной стороны — ORM бы туда, было бы классно, НО! ORM мало, и нужен не он! Почти все существующие ORM-движки (кроме разве что [https://docs.djangoproject.com/en/dev/topics/db/models/ Django Models]) — это просто объектный интерфейс к базе данных. А нужно некое объектное ядро, которое бы позволяло создавать свои объекты, с полями различных типов, в том числе и ссылающимися на другие объекты, с возможностью приписывания специальных особенностей полям, с общими механизмами хранения истории, рассылки уведомлений, системой прав и с автоматическим базовым CRUD-интерфейсом. | ||
− | + | == Идеи по созданию объектного ядра == | |
− | + | === Объекты в Bugzilla === | |
− | + | * баг | |
+ | * классификация, продукт, компонент | ||
+ | * тег (ключевое слово / keyword), milestone, версия, статус бага, agreement (пример кастомного поля) | ||
+ | * вложение, комментарий, флаг, тип флага | ||
+ | * пользователь, группа | ||
+ | * если таки будет ядро — ещё появляется метакласс сущности, объекты которого описывают типы сущностей | ||
− | + | <graph> | |
− | + | digraph G { | |
− | + | Классификация -> Продукт -> Компонент -> Баг; | |
+ | Продукт -> Версия -> Баг; | ||
+ | Продукт -> Milestone -> Баг; | ||
+ | Продукт -> Agreement -> Баг; | ||
+ | Продукт -> Тег; | ||
+ | Продукт -> "Тип флага" -> Флаг; | ||
+ | Статус -> Баг; | ||
+ | Баг -> Коммент; | ||
+ | Баг -> Вложение; | ||
+ | Баг -> Флаг; | ||
+ | Баг -> Тег [dir=both, color=blue]; | ||
+ | Баг [shape=box, style=filled, fillcolor="#ffe0e0"]; | ||
+ | Продукт [shape=box]; | ||
+ | } | ||
+ | </graph> | ||
− | + | Причём, понятное дело, если баг принадлежит к некоторому продукту (через компонент), то и его версия, milestone, agreement должны принадлежать к тому же продукту. Сейчас в Bugzilla это реализуется так — для каждой сущности, связанной с багом, в баге есть «поле», а для ограничения значений полей поля делаются «зависимыми» от других полей. Из-за этого там куча костылей и, по сути, повесить зависимость на отличное от поля «продукт» поле невозможно. | |
− | + | === Минусы текущей реализации === | |
− | + | Чем плоха текущая багзильная реализация этого «добра»? | |
− | + | Очень просто: '''почти ни хрена не настраивается''' - нельзя ни добавить свои возможности, ни отрубить ненужные встроенные. Ибо всё жёстко и криво (хардкод). А ещё: | |
− | + | * История хранится только для багов, но не для остальных объектов. | |
− | * | + | * Шаблоны переусложнены. |
− | * | + | * Нет "объектов", есть «значения полей», соответсвенно, им не добавишь атрибутов и не навесишь логики. |
− | [[ | + | * Значения кастом полей в таблице багов хранятся не ссылками по ID, а по именам, что создаёт геморрой для зависимых полей, так как чтобы точно идентифицировать значение, приходится брать ещё и значение поля, от которого оно зависит. |
+ | * Для выпадающих списков есть как «контроль значений», так и «контроль видимости поля», что в корне '''''неверно'''''! Типа поле скрыто, но при этом есть варианты, которые можно выбрать? Бред! Или наоборот — поле доступно, но из вариантов — только пустое значение. | ||
+ | * По факту, ни от чего, кроме продукта, зависимым значение не сделаешь. | ||
+ | * Код полей не генерится автоматически, а ручками вписываются в шаблоны. | ||
+ | * На всё это навёрнута туча неструктурированного кода, определяющего поведение «встроенных» полей. | ||
+ | |||
+ | === Проект супер-объектного-ядра === | ||
+ | |||
+ | Что предлагается сделать: | ||
+ | * Есть объекты. У объектов есть поля (разных типов). В том числе, есть типы «multi-select» и «single-select», ссылающиеся на другие объекты. | ||
+ | * Зависимости полей могут прописываться дополнительно, в виде ограничений вида: «баг.компонент.продукт == баг.продукт». Могут и не прописываться. Теоретически, могут прописываться несколько ограничений на одно поле, например, чтобы какой-нибудь атрибут зависел и от продукта, и от, скажем, операционной системы. Такое устройство наиболее гибкое и в частности позволяет багу иметь несколько полей, ссылающихся на один тип объектов. | ||
+ | * Поля могут скрываться в зависимости от значений других полей. Селект-поля скрываются, если в них по зависимостям нечего выбирать. На поля остальных типов можно вешать «настройку видимости», подобную текущей багзильной реализации — просто тупо «поле = одно из значений…». | ||
+ | * HTML-код полей должен генерироваться автоматически. Также желательна возможность задавать группировку полей в интерфейсе — например, опционально раскрываемые «Advanced Fields» (только общим fieldset’ом, а не как сейчас — просто скрытие полей в разных местах формы). | ||
+ | * На поля можно назначить дополнительные обработчики, задающие более хитрое поведение. Сами обработчики пишутся в коде, по возможности — максимально абстрагированно от конкретного поля. Назначаться они при этом должны не из кода, а из интерфейса конфигурации модели. На этих дополнительных обработчиках должно работать всё! Примеры: | ||
+ | ** Платформа, ОС: функции угадывания значения по умолчанию на основе заголовков запроса. | ||
+ | ** Статус: есть ограничения переходов из состояния в состояние (workflow). Возможно, его нужно попытаться вынести в базовые настройки модели. | ||
+ | ** CC: специальное поведение при клонировании, смене Assignee и QA (старые добавляются в CC), специальное «значение по умолчанию», зависящее от компонента. Возможно, зависимые значения по умолчанию стоит как-то протащить в общее ядро, но это чуть более тонкий момент, чем всё остальное. | ||
+ | ** Keywords/теги: автосоздание новых значений. | ||
+ | * История хранится централизованно для всех объектов. | ||
+ | * Общий механизм рассылки изменений по почте для всех объектов каким-либо образом «связанным» пользователям. Настройки уведомлений на уровнях: событие (изменено значение поля, добавлена сущность) и отношение (собственно связь). | ||
+ | * Поиск: адаптировать сильно прокачанный движок поиска из [http://wiki.4intra.net/Bugzilla4Intranet Bugzilla4Intranet]. Адаптировать долго не придётся, потому что с точки зрения read-only все типы полей останутся, по сути, те же самые. С другой стороны, его нужно обобщить, так что кое-что сделать всё-таки будет нужно. Но зато в итоге получится супер-инструмент — система выборок, которая отлично хавает большие базы, сложные ''и произвольные'' структуры запросов и не давится :) (доказано Bugzilla4Intranet) | ||
+ | * Права доступа: Нужна опять-таки общая схема для всех объектов, с одной стороны, простая для вычисления системой, а с другой стороны, дающая достаточную гибкость разных настроек. По всей видимости, нужны с одной стороны опять-таки «связанные» пользователи, а с другой стороны — роли. Причём, пользователи могут быть «связанные» через какое-то поле — например, человек может быть связан с багом, потому что прописан как Global Watcher для продукта этого бага. Роли могут набираться из действий над полями различных объектов и права на просмотр объектов. Возможно, нужно давать возможность разграничивать доступ на просмотр к разным полям — например, в Bugzilla только группа time-tracker’ов может посмотреть информацию о рабочем времени. | ||
+ | |||
+ | Таким образом наш трекер превратится, по сути, в модульное приложение, построенное вокруг очень прокачанного автоинтерфейса полей и объектов. Естественно, это уже не Bugzilla ни разу, но зато чем-то похоже на [http://roundup.sourceforge.net/ Roundup] — «конструктор трекеров». Однако и с ним различий много — roundup не умеет зависимых селект-полей, модель задаётся в коде, права доступа слабые, поиск слабый. | ||
+ | |||
+ | === Обновление модели === | ||
+ | |||
+ | Обновление базы багзильское (тупая последовательность операций): | ||
+ | * (+) Очевидный порядок обновлений, нет проблем с их зависимостями друг от друга (новые просто дописываются в конец, порядок всегда правильный) | ||
+ | * (-) Не проверяется, корректна ли схема БД после обновлений | ||
+ | * (-) Обновления задаются именно для SQL БД, а не для метамодели | ||
+ | * (-) Не очень красивая портянка в функции обновления БД | ||
+ | |||
+ | Обновление базы наше: | ||
+ | * AddType -> RenameFields -> AddFields -> ChangeFields -> DropFields | ||
+ | * ChangeFields с помощью функций обновления | ||
+ | * (???) Самый интересный вопрос - как сделать функции обновления не на SQL, в условиях когда модель в неконсистентном и вообще не знает, в каком состоянии? | ||
+ | * После каждого шага запуск хука | ||
+ | * Переименования задаются декларативно | ||
+ | * Возможность Dry Run, просмотра и проверки последовательности обновлений | ||
+ | * Зависимости обновлений в рамках каждого шага можно задать декларативно (хотя ситуация редкая) | ||
+ | *: А может, просто стоит задавать их в ассоциативном массиве по порядку | ||
+ | * Ещё может быть, что обновление одного типа зависит от обновления другого (причём это уже более частая ситуация) | ||
+ | |||
+ | === Модель === | ||
+ | |||
+ | Получается, что ядро модели состоит из следующих таблиц: | ||
+ | * Типы объектов | ||
+ | ** Название типа | ||
+ | ** Дополнительное поведение типа | ||
+ | * Поля | ||
+ | ** Ссылка на объект | ||
+ | ** ID поля | ||
+ | ** Название поля | ||
+ | ** Тип поля | ||
+ | ** Nullable? Т.е. разрешено ли пустое значение | ||
+ | ** Поле этого же объекта, контролирующее видимость данного (для не-select полей) | ||
+ | ** Связи поля (для select-полей) | ||
+ | ** Дополнительное поведение поля | ||
+ | * Контроль видимости полей | ||
+ | ** Ссылка на поле | ||
+ | ** ID объекта, для которого оно видно | ||
+ | * Транзакции (группы изменений) | ||
+ | ** Момент времени | ||
+ | ** Изменивший пользователь | ||
+ | * История изменений | ||
+ | ** Ссылка на транзакцию | ||
+ | ** Тип объекта | ||
+ | ** Ссылка на объект | ||
+ | ** Ссылка на поле (кроме добавления объекта) | ||
+ | ** Старое значение | ||
+ | ** Новое значение | ||
+ | * Один неудаляемый тип — пользователи (их поля, тем не менее, можно менять) | ||
+ | * Связи объектов с пользователями | ||
+ | ** ID связи | ||
+ | ** Название связи | ||
+ | ** Ссылка на объект | ||
+ | ** Цепочка свойств, заканчивающаяся объектом «пользователь» | ||
+ | * Пользовательские настройки оповещений | ||
+ | ** Ссылка на пользователя (либо пустая для настроек по умолчанию) | ||
+ | ** Ссылка на связь | ||
+ | ** Тип события: добавление/удаление/изменение | ||
+ | ** Ссылка на поле объекта (может быть пустая) | ||
+ | * Роли (или группы, что примерно то же самое) | ||
+ | ** Включаемые роли | ||
+ | ** Включаемые разрешения | ||
+ | * Разрешения (из которых состоят роли) | ||
+ | ** Ссылка на связь | ||
+ | ** Тип разрешения: просмотр/создание/удаление/изменение | ||
+ | ** Ссылка на поле объекта (пустая = весь объект) | ||
+ | ** Ссылка на значение поля (пустая = любое) | ||
+ | |||
+ | === Типы полей === | ||
+ | |||
+ | <tab sep="bar" class="wikitable" head="top"> | ||
+ | Тип | Параметры | Представления | ||
+ | Строка | Длина | Input, textarea, rich edit | ||
+ | Логический | | Флажок | ||
+ | Числовой | Точность (M.N) | Input | ||
+ | Дата и/или время | Дата? Время? | Поле со всплывающим календарём, просто календарь, просто поле | ||
+ | Файл | | Поле загрузки файла | ||
+ | Single-select | Тип объекта | Радиобатон, HTML-селект | ||
+ | Multi-select | Тип объекта | HTML-мультиселект, флажки, комбо-бокс | ||
+ | </tab> | ||
+ | |||
+ | == Текущее состояние == | ||
+ | |||
+ | Базовые поля (то, чего не быть логически не может): | ||
+ | * Объект, баг, пользователь, группа, комментарий к багу. | ||
+ | * Продукт имеет специальный смысл — разграничение прав. Поэтому он тоже обязателен. | ||
+ | |||
+ | У каждого поля есть: | ||
+ | * Тип | ||
+ | * Значение по умолчанию | ||
+ | * Вид показа в интерфейсе (по умолчанию?) | ||
+ | * Копируется ли значение атрибута при клонировании | ||
+ | * Показывается ли атрибут в форме создания | ||
+ | * Ссылка на контролирующий атрибут того же объекта, что и этот, и на его значения | ||
+ | *: Если выбрано, означает, что атрибут показывается, только если другой атрибут той же сущности, которой принадлежит этот, имеет одно из заданных значений | ||
+ | |||
+ | Типы атрибутов: | ||
+ | * {{ok}} Строка | ||
+ | * Boolean | ||
+ | * {{ok}} Десятичное число | ||
+ | * Дата | ||
+ | * Время | ||
+ | * {{ok}} Дата+время | ||
+ | * Файл (вложение) | ||
+ | * Single-Select → ссылка на сущность (то есть «многие к 1») | ||
+ | * Multi-Select → ссылка на несколько сущностей одного типа (то есть «многие ко многим») | ||
+ | ** Два способа показа — поле со списком (комбобокс), или мультиселект | ||
+ | * Список тегов, с автодобавлением значений | ||
+ | |||
+ | == Существующие поля == | ||
+ | |||
+ | === Поля багов === | ||
+ | |||
+ | Поля багов перечислены ниже. Жирное «да» в колонке «можно отключить» означает, что отключать можно уже сейчас (скорее всего, через параметры типа usevotes и т. п.). Нежирное «да» в колонках «можно отключить» и «можно менять тип» означают, что чисто теоретически логика работы Bugzilla это позволяет. | ||
+ | <tab sep=bar class=simpletable head=topleft> | ||
+ | поле | тип | можно отключить? | можно менять тип? | примечания | ||
+ | short_desc | строка | нет | нет | | ||
+ | classification | single-select | '''да''' | нет | | ||
+ | product | single-select | да | нет | контролируется classification (или никем), у поля есть привязка к правам пользователя | ||
+ | component | single-select | да | нет | контролируется product | ||
+ | version | single-select | да | да | контролируется product, если тип = single-select. значение по умолчанию контролируется component | ||
+ | rep_platform | single-select | '''да''' | да | специальная функция «угадывания» дефолтного значения | ||
+ | bug_file_loc | строка | да | да | | ||
+ | op_sys | single-select | '''да''' | да | специальная функция «угадывания» дефолтного значения | ||
+ | bug_status | single-select | нет | нет | есть функция валидации (Bug Status Workflow) | ||
+ | resolution | single-select | да | нет | у атрибута есть контролирующая видимость сущность (показывается только при bug_status.closed=1) | ||
+ | status_whiteboard | строка | да | да | | ||
+ | keywords | multi-select | да | да | показ в виде списка | ||
+ | bug_severity | single-select | да | нет | | ||
+ | priority | single-select | да | да | есть желание сделать decimal | ||
+ | assigned_to | single-select | нет | нет | ссылка на пользователя. значение по умолчанию контролируется component | ||
+ | reporter | single-select | нет | нет | ссылка на пользователя | ||
+ | qa_contact | single-select | '''да''' | нет | ссылка на пользователя. значение по умолчанию контролируется component | ||
+ | votes | decimal(,0) | '''да''' | нет | | ||
+ | cc | multi-select | да | нет | ссылка на пользователей. значение по умолчанию контролируется component | ||
+ | dependson | multi-select | да | нет | ссылка на баги. показ в виде списка | ||
+ | blocked | multi-select | да | нет | ссылка на баги. показ в виде списка | ||
+ | target_milestone | single-select | да | да | контролируется product, если тип = single-select | ||
+ | see_also | multi-select | да | да | ссылка на баги. показ в виде списка (багов), если тип = single-select | ||
+ | alias | строка | '''да''' | да | | ||
+ | reporter_accessible | boolean | нет | нет | | ||
+ | cclist_accessible | boolean | нет | нет | | ||
+ | estimated_time | время | '''да''' | нет | | ||
+ | remaining_time | время | '''да''' | нет | | ||
+ | deadline | дата | '''да''' | нет | | ||
+ | creation_ts | дата+время | нет | нет | | ||
+ | delta_ts | дата+время | нет | нет | | ||
+ | cf_agreement | single-select | '''да''' | да | контролируется product | ||
+ | *** нет в fielddescs *** | | ||
+ | lastdiffed | дата+время | нет | нет | скрыто в интерфейсе | ||
+ | attachments | multi-select | нет | нет | 1 ко многим | ||
+ | longdescs | multi-select | нет | нет | 1 ко многим | ||
+ | flags | multi-select | да | нет | 1 ко многим | ||
+ | </tab> | ||
+ | |||
+ | Примечания: | ||
+ | * Все поля-ссылки на пользователей показываются в виде строки либо в виде combo-box’а, и у них есть функция валидации — она угадывает юзеров по некорректным именам. | ||
+ | |||
+ | ==== Логически минимальный набор полей ==== | ||
+ | |||
+ | Совершенно точно, никогда и ни при каких условиях у бага не могут отсутствовать поля: | ||
+ | * ID | ||
+ | * Заголовок | ||
+ | * История => reporter, время создания (creation_ts), время изменения (delta_ts), время оповещения по почте (lastdiffed) | ||
+ | * Комментарии | ||
+ | Без этого никакой «баг» смысла не имеет ни в одном баг-трекере. | ||
+ | |||
+ | ==== Устаревшие поля ==== | ||
+ | |||
+ | Устаревшие поля / поля, которые ХЗ зачем нужны в таблице полей багов: | ||
+ | * assignee_accessible | ||
+ | * qacontact_accessible | ||
+ | * longdesc | ||
+ | * commenter | ||
+ | * longdescs.isprivate | ||
+ | * content | ||
+ | * bug_group | ||
+ | * flagtypes.name | ||
+ | * requestees.login_name | ||
+ | * setters.login_name | ||
+ | |||
+ | ==== Вычисляемые поля ==== | ||
+ | |||
+ | Вычисляемые поля багов: | ||
+ | <tab sep=bar class=simpletable head=left> | ||
+ | work_time | Сумма work_time от связанных longdescs | ||
+ | percentage_complete | (Сумма work_time от dependson)/(Сумма estimated_time от dependson) | ||
+ | owner_idle_time | Текущая дата минус MAX(дата последнего коммента от Assignee, дата последней активности от Assignee) | ||
+ | days_elapsed | Текущая дата минус delta_ts | ||
+ | everconfirmed | Менялся ли статус хоть раз на != UNCONFIRMED | ||
+ | </tab> | ||
+ | |||
+ | === Поля вложений === | ||
+ | |||
+ | <tab sep=bar class=simpletable head=left> | ||
+ | submitter | single-select, показ в виде select’а или строки, есть функция валидации (угадывания юзера по некорректному имени) | ||
+ | description | строка | ||
+ | filename | строка | ||
+ | mimetype | строка | ||
+ | ispatch | boolean | ||
+ | isobsolete | boolean | ||
+ | isprivate | boolean | ||
+ | isurl | boolean | ||
+ | thedata | потенциально строка, а вообще-то обычно NULL, так как данные хранятся в локальных файлах | ||
+ | </tab> | ||
+ | |||
+ | === Поля компонентов === | ||
+ | |||
+ | <tab sep=bar class=simpletable head=top> | ||
+ | поле | тип | можно отключить? | можно менять тип? | примечания | ||
+ | name | строка | нет | нет | | ||
+ | initialowner | single-select | да | нет | ссылка на пользователя | ||
+ | initialqacontact| single-select | да | нет | ссылка на пользователя | ||
+ | initialcc | multi-select | да | нет | ссылка на пользователей | ||
+ | default_version | single-select | да | нет | ссылка на версию | ||
+ | description | строка | да | да | | ||
+ | product_id | single-select | нет | нет | | ||
+ | wiki_url | строка | да | нет | | ||
+ | is_active | boolean | да | нет | | ||
+ | </tab> | ||
+ | |||
+ | == Из чего состоит багзилла? == | ||
+ | |||
+ | === С внешней точки зрения === | ||
+ | |||
+ | Крупные блоки функционала в Bugzilla с точки зрения пользователя: | ||
+ | |||
+ | * Создание, просмотр, изменение багов, история по багу | ||
+ | ** Форматирование комментариев | ||
+ | * Создание, просмотр, изменение вложений | ||
+ | * Поиск багов, форма поиска | ||
+ | * Графики одни, графики другие, Summarize Time | ||
+ | * Исходящая почта | ||
+ | * Входящая почта | ||
+ | * Запросы флагов | ||
+ | * Напоминания (whining) | ||
+ | * Регистрация, изменение, раздача групп пользователям | ||
+ | * Пользовательские настройки | ||
+ | * ''XML-импорт (в полудохлом виде)'' | ||
+ | * Web-сервисы (XML-RPC, JSON-RPC) | ||
+ | * Sanity Check | ||
+ | * Графы и деревья зависимостей | ||
+ | * Голосование за баги | ||
+ | |||
+ | ==== Наши крупные фичи ==== | ||
+ | |||
+ | * SCRUM-карточки | ||
+ | * RSS-лента активности | ||
+ | * XML-Simple Web-сервисы | ||
+ | * Проверки корректности | ||
+ | * Excel-импорт | ||
+ | * Информер | ||
+ | * Глобальная авторизация | ||
+ | * Today Worktime, Super Worktime | ||
+ | |||
+ | Плюс вагон и маленькая тележка мелочи. | ||
+ | |||
+ | === Страница создания бага (enter_bug.cgi) === | ||
+ | |||
+ | Текущая логика страницы создания бага: | ||
+ | |||
+ | * выбор classification, если она включена | ||
+ | * classification выбрана → выбор product, если он не вообще один | ||
+ | * тот же выбор продукта/классификации при клонировании багов | ||
+ | * продукт выбран → форма создания бага | ||
+ | * показ корректных списков возможных значений полей: | ||
+ | ** типы флагов в зависимости от компонента | ||
+ | ** cf_agreement в зависимости от продукта | ||
+ | ** списки пользователей, относящихся к багу в combo-box’ы | ||
+ | ** опциональный запрет на ввод приоритета на основе конфигурации (letsubmitterchoosepriority) | ||
+ | ** список флажков — ограничителей доступа группами | ||
+ | * значения полей по умолчанию: | ||
+ | ** которые совсем по умолчанию | ||
+ | ** угадывание op_sys и rep_platform на основе заголовков запроса | ||
+ | ** версия, qa_contact, assigned_to, cc по умолчанию для компонента | ||
+ | ** хитрая логика для изменения списков cc при выборе компонентов | ||
+ | ** assigned_to=ты при выборе статуса ASSIGNED | ||
+ | ** показ поля resolution при выборе закрытого статуса | ||
+ | ** версия из cookies | ||
+ | ** загруженные из шаблона ввода бага | ||
+ | ** загруженные из клонированного бага | ||
+ | *** ссылка на старый аттач в описании нового клонированного бага | ||
+ | *** хитрая логика для CC при клонировании багов | ||
+ | * напоминания о вводе времени | ||
+ | * предпросмотр комментариев | ||
+ | * добавление ссылки на старый аттач для клонированного из коммента бага | ||
+ | * переключатель Show Expert Fields | ||
+ | * Submit по Ctrl-Enter | ||
+ | |||
+ | === Обработчик создания бага (post_bug.cgi) === | ||
+ | |||
+ | * Редирект на enter_bug.cgi если форма не заполнена | ||
+ | * Проверка, не был ли уже использован этот token для постановки другого бага? | ||
+ | * Вывод страницы с URL-шаблоном постановки бага, если попросили | ||
+ | * Заполнение описания по шаблону, если использовался спецвид формы (например create_guided) | ||
+ | * Отправка куки VERSION | ||
+ | * Начало/конец транзакции в БД | ||
+ | * Постановка собственно бага (Bug::create) | ||
+ | * Постановка вложения сразу при создании бага | ||
+ | * Постановка флагов на вложение | ||
+ | * Постановка флагов на баг | ||
+ | * Рассылка почты по багу, по его зависимостям | ||
+ | * Вывод сообщения о том, что баг поставлен, о том, что CC-список обрезан по группе | ||
+ | |||
+ | === Обработчик изменения бага (process_bug.cgi) === | ||
+ | |||
+ | * Начало/конец транзакции в БД | ||
+ | * SELECT FOR UPDATE багов | ||
+ | * Удаление значений полей, равных dontchange (используется в групповом редактировании) | ||
+ | * Угадывание юзеров по части логина/имени | ||
+ | * Проверка коллизии по delta_ts, вывод только действительно изменённых полей в форму подтверждения | ||
+ | * Проверка token формы | ||
+ | * Загрузка следующего бага из списка ДО обновления текущего (O_O) | ||
+ | * Проверка прав редактирования по всем багам | ||
+ | * Установка значения продукта до всех остальных полей | ||
+ | * Установка новых групп до остальных изменений, когда включён strict_isolation | ||
+ | * Установка/изменение флагов | ||
+ | * Установка зависимостей бага | ||
+ | * Установка ключевых слов | ||
+ | * Установка остальных полей | ||
+ | * Установка некоторых значений только для обновлений отдельных багов (alias, cclist_accessible, reporter_accessible, isprivate на комментах) | ||
+ | * БОльшая часть логики обновления поля CC | ||
+ | * Вызов функции проверки strict_isolation | ||
+ | * Перемещение багов (MOVE) — полуживое, хз как работает | ||
+ | * И после всего этого — ещё изменения, status, resolution, dup_id | ||
+ | * Теперь всё это ещё незакоммичено, вызов реальных обновлений из Bug.pm | ||
+ | * Отправка почты по зависимостям, если статус поменялся с открытого на закрытый | ||
+ | * Обрезание CC-списка по группе (наше) | ||
+ | * Сообщение, если очищено remaining_time | ||
+ | * Удаление голосов за баг, если переместили в другой продукт, и проверка голосо-подтвеждённости бага | ||
+ | * Отправка почты CC, Assignee, Reporter’у, QA, старым Assignee, QA и CC | ||
+ | * Отправка почты по багу, дубликатом которого был помечен данный | ||
+ | * Добавление нескольких вложений (наше) | ||
+ | * Отправка почты по флагам, через отдельный механизм сбоку | ||
+ | * Редирект (наше) или показ следующего/того же/никакого бага | ||
+ | * Не показывает ничего, если USAGE_MODE_EMAIL | ||
+ | |||
+ | === Список/поиск багов (buglist.cgi) === | ||
+ | |||
+ | * SuperWorkTime (наше доработко) | ||
+ | * Редирект на форму поиска для пустого запроса | ||
+ | * Редирект на форму поиска с добавленными пустыми полями, если на форме поиска жмут Add/Remove поле без JS | ||
+ | * Редирект с POST’енного запроса на GET | ||
+ | * Быстрый поиск | ||
+ | * Посыл на хрен, если content пуст при включённом параметре specific_search_allow_empty_words | ||
+ | * Обратная совместимость: format=rdf -> ctype=rdf, ctype=rss -> ctype=atom | ||
+ | * ctype=js слать в хрен | ||
+ | * Поддержка server-push | ||
+ | * regetlastlist — открытие последнего просмотренного списка багов (берётся из куки) | ||
+ | * Удаление колонки relevance из списка колонок, если юзер не просит полнотекстовый поиск | ||
+ | * В buglist.cgi почему-то тусуются функции InsertNamedQuery, LookupSeries, GetQuip, GetGroups | ||
+ | * Генерация имени файла, если попросили список не в html-формате | ||
+ | * Выполнение запросов поиска | ||
+ | * Сохранение и удаление сохранённых запросов из БД | ||
+ | * Запуск series | ||
+ | * Если сохранённый запрос не говорил нам свой формат, решаем что advanced | ||
+ | * Вкуривание списка колонок (длинное, тварь) | ||
+ | * Определение порядка сортировки | ||
+ | * Подсчёт сумм значений полей таймтрекинга | ||
+ | * Проверка доступа к багам и установка значения в implied или manual (х.з зачем нужно) | ||
+ | * Массовое редактирование багов, в частности сборка пересечений доступных значений полей | ||
+ | * Кодировка CSV (наше доработко) | ||
+ | |||
+ | === Система прав === | ||
+ | |||
+ | Какие в Bugzilla есть права / ограничения доступа? | ||
+ | |||
+ | * Права доступа к продуктам | ||
+ | ** MANDATORY / SHOWN / DEFAULT / NA | ||
+ | ** Entry | ||
+ | ** Canedit | ||
+ | ** Editcomponents | ||
+ | ** Canconfirm | ||
+ | ** Editbugs | ||
+ | * Private комментарии — видны только инсайдер-группе | ||
+ | * Информация о таймтрекинге — видна только группе, списывающей время | ||
+ | * reporter_accessible, cclist_accessible на отдельных багах | ||
+ | * Опциональные группы на отдельных багах | ||
+ | * Права на правку отдельных групп | ||
+ | * Права editclassifications, editcomponents, editfields, editkeywords, editusers | ||
+ | |||
+ | === Настройки оповещений о багах === | ||
+ | |||
+ | Отношения: | ||
+ | * Assignee, QA, Reporter, CC | ||
+ | * Requestee или Setter флага (реально в Bugzilla прикручено сильно сбоку) | ||
+ | * По идее — также создатель аттачмента, коммента (если разрешать править) | ||
+ | * Watcher указанного выше | ||
+ | * Global Watcher | ||
+ | |||
+ | События: | ||
+ | * Добавлен/удалён из указанного выше | ||
+ | * Изменено одно из полей бага (м.б отдельные настройки, м.б вместе) | ||
+ | * Баг / блокирующий баг меняет статус с закрытого на открытый или обратно | ||
+ | * «Но кроме» UNCONFIRMED | ||
+ | * «Но кроме» своих изменений | ||
+ | |||
+ | == Что не так? == | ||
+ | |||
+ | Что в Bugzilla не так? Что нужно поменять, чтобы она перестала быть говном? | ||
+ | |||
+ | Да, я знаю, что почти всё, но дело не в этом — дело в том, что создавать систему «от противного» — есть хороший тон, ведущий к прогрессу. | ||
+ | |||
+ | === Ядро === | ||
+ | |||
+ | Самое жирное «не так» в Bugzilla — это слабость ядра. Если бы ядро было прокачанным, как в начале статьи, оно бы заменило: | ||
+ | |||
+ | * Custom Fields, то есть, управление полями багов. | ||
+ | * Отключение стандартных полей типа OS, Hardware. | ||
+ | * Добавление спецполей в продукты, компоненты и т. д. — сейчас это делается в коде. | ||
+ | * Версионирование всех объектов. История бы хранилась унифицированно. Не было бы отдельно таблиц bugs_activity и longdescs, соответственно не было бы и тормозов при проверке «Only bugs changed between…» либо комментарии бы дублировались в bugs_activity (логичнее) | ||
+ | * Отправка почты, которая сейчас отправляется через 2 разных места. | ||
+ | * Простые интерфейсы типа CRUD (Create/Read/Update/Delete), сейчас созданные непонятно каким копипастом. В основном имеется ввиду админка. | ||
+ | * Система прав стала бы и проще (по сравнению с хрен-пойми-системой Mandatory/Default/Shown/NA), и имела бы больше возможностей. | ||
+ | * Валидаторы и подсказки значений. | ||
+ | * Корректная валидация зависимостей полей друг от друга. | ||
+ | * Часть SQL-запросов, написанных ручками в коде. | ||
+ | * Вся логика постановки/обновления багов из process_bug и post_bug, дублированная сейчас в обработке входящих e-mailов и Excel-импорте | ||
+ | * Даже Excel- и XML-импорт, причём импортировать можно было бы вообще всё что угодно. | ||
+ | |||
+ | Появились бы дополнительные возможности: | ||
+ | |||
+ | * Создание новых объектов типа SCRUM карточек. | ||
+ | * Изменение типов стандартных полей типа целочисленных приоритетов. | ||
+ | * Можно было бы прикрутить статистику по любым объектам, причём с Time Machine, то есть просмотром статистики за любой прошедший момент времени. :) | ||
+ | |||
+ | === Внешности === | ||
+ | |||
+ | * Большая часть интерфейсов нуждается в полной переделке. Например: | ||
+ | ** На форме бага «Show Advanced Fields» должно быть сделано отдельной группкой полей (fieldset), а не скрытием полей прямо посреди формы в разных местах (пугает). | ||
+ | ** Страница настройки прав продукта — мегастрёмная. Таблица с группами там на хрен не нужна никому вообще. | ||
+ | ** Частично относится к ядру, но — интерфейс редактирования «контроля значений» кастом-полей это сейчас полная жесть — например, нельзя посмотреть список значений кастом поля для конкретного продукта (от которого зависят наборы значений). | ||
+ | * Историю изменений бага показывать вперемешку с комментариями к багу (а-ля Trac). Туда же можно заинтегрировать и замешать коммиты из системы контроля версий. | ||
+ | * Добавить ленту обновлений по багам, поиск «последних багов», что-то типа форум-функциональности. | ||
+ | * Возможно, добавить Grid View с возможностью массовых обновлений в поиске. | ||
+ | * Отрефакторить кучу действий, связанных с поиском, расположенных под списком багов. | ||
+ | * Keywords переделать в «теги», то есть, сделать, чтобы они сами заводились новые. | ||
+ | * <s>Заменить YUI на jQuery</s> в Bugzilla4Intranet уже, форму поиска сгруппировать (но не так, как в 4.0), сделать почти все фильтры добавляемыми, добавляемыми через JS, чтобы не перезагружалась страница каждый раз | ||
+ | * Документацию «насытить» в вики, POD-документацию по коду туда же. | ||
+ | |||
+ | === Кишки, кроме ядра === | ||
+ | |||
+ | * Добавить глобальный объект статуса, в который сохранять почту, которую нужно отправить, и сообщения, которые сейчас руками сохраняются в сессию. | ||
+ | * Использовать не CGI, а хеши параметров запроса, это улучшает и производительность, и переносимость, и спасает от кучи глюков, так как например, $cgi->param может вернуть как список, так и скаляр | ||
+ | * Использовать не кучу CGI-скриптов, а несколько (мало) точек входа и классы, всю мохнатую логику перенести в них. Не использовать модуль CGI.pm вообще (!), потому что он прости господи даже без use strict написан и порождает некоторые глюки сам по себе. В крайней форме точки доступа — это один index.cgi, позволяющий работать через CGI, один server.fcgi (FastCGI), один модуль для апача, и м.б. один для HTTP::Server::Simple. Ибо по сути, интерфейс «запроса» тривиален и не требует никакого бешеного CGI. | ||
+ | * Убрать ВСЕ строки (terms и т. п.) и описания ошибок из шаблонов и «длинного if’а», добавить отдельный уровень «локализации» / «таблицы строк», и переместить всё это в него. Потенциально также переместить туда же вообще все строки/тексты из шаблонов, для лёгкой локализации. | ||
+ | * Обязательно оставить совместимость с PostgreSQL, но генерилка запросов не должна на это рассчитывать и должна работать оптимальнее, чем сейчас, например, в смысле дурацких подзапросов assigned_to=(select id from profiles where login_name=?) и т. п. | ||
+ | * Желательно заменить Template::Toolkit на что-нибудь, хотя бы даже на моё поделие VMX::Template, чтобы не общаться с этим тормозом. Но как МИНИМУМ, даже если не заменять — убрать ВСЮ обратную связь с БД из шаблонов, ибо именно она убивает производительность в первую очередь! Ну ладно, не в первую, а во вторую, после дурацкого движка поиска. Хотя это и будет уже не MVC, а MVP :) |
Текущая версия на 12:09, 24 июля 2012
В Bugzilla половина кода в шаблонах, половина на основе полу-ORM’а Bugzilla::Object. Большая часть — говнокод. С одной стороны — ORM бы туда, было бы классно, НО! ORM мало, и нужен не он! Почти все существующие ORM-движки (кроме разве что Django Models) — это просто объектный интерфейс к базе данных. А нужно некое объектное ядро, которое бы позволяло создавать свои объекты, с полями различных типов, в том числе и ссылающимися на другие объекты, с возможностью приписывания специальных особенностей полям, с общими механизмами хранения истории, рассылки уведомлений, системой прав и с автоматическим базовым CRUD-интерфейсом.
Содержание
Идеи по созданию объектного ядра
Объекты в Bugzilla
- баг
- классификация, продукт, компонент
- тег (ключевое слово / keyword), milestone, версия, статус бага, agreement (пример кастомного поля)
- вложение, комментарий, флаг, тип флага
- пользователь, группа
- если таки будет ядро — ещё появляется метакласс сущности, объекты которого описывают типы сущностей
Причём, понятное дело, если баг принадлежит к некоторому продукту (через компонент), то и его версия, milestone, agreement должны принадлежать к тому же продукту. Сейчас в Bugzilla это реализуется так — для каждой сущности, связанной с багом, в баге есть «поле», а для ограничения значений полей поля делаются «зависимыми» от других полей. Из-за этого там куча костылей и, по сути, повесить зависимость на отличное от поля «продукт» поле невозможно.
Минусы текущей реализации
Чем плоха текущая багзильная реализация этого «добра»?
Очень просто: почти ни хрена не настраивается - нельзя ни добавить свои возможности, ни отрубить ненужные встроенные. Ибо всё жёстко и криво (хардкод). А ещё:
- История хранится только для багов, но не для остальных объектов.
- Шаблоны переусложнены.
- Нет "объектов", есть «значения полей», соответсвенно, им не добавишь атрибутов и не навесишь логики.
- Значения кастом полей в таблице багов хранятся не ссылками по ID, а по именам, что создаёт геморрой для зависимых полей, так как чтобы точно идентифицировать значение, приходится брать ещё и значение поля, от которого оно зависит.
- Для выпадающих списков есть как «контроль значений», так и «контроль видимости поля», что в корне неверно! Типа поле скрыто, но при этом есть варианты, которые можно выбрать? Бред! Или наоборот — поле доступно, но из вариантов — только пустое значение.
- По факту, ни от чего, кроме продукта, зависимым значение не сделаешь.
- Код полей не генерится автоматически, а ручками вписываются в шаблоны.
- На всё это навёрнута туча неструктурированного кода, определяющего поведение «встроенных» полей.
Проект супер-объектного-ядра
Что предлагается сделать:
- Есть объекты. У объектов есть поля (разных типов). В том числе, есть типы «multi-select» и «single-select», ссылающиеся на другие объекты.
- Зависимости полей могут прописываться дополнительно, в виде ограничений вида: «баг.компонент.продукт == баг.продукт». Могут и не прописываться. Теоретически, могут прописываться несколько ограничений на одно поле, например, чтобы какой-нибудь атрибут зависел и от продукта, и от, скажем, операционной системы. Такое устройство наиболее гибкое и в частности позволяет багу иметь несколько полей, ссылающихся на один тип объектов.
- Поля могут скрываться в зависимости от значений других полей. Селект-поля скрываются, если в них по зависимостям нечего выбирать. На поля остальных типов можно вешать «настройку видимости», подобную текущей багзильной реализации — просто тупо «поле = одно из значений…».
- HTML-код полей должен генерироваться автоматически. Также желательна возможность задавать группировку полей в интерфейсе — например, опционально раскрываемые «Advanced Fields» (только общим fieldset’ом, а не как сейчас — просто скрытие полей в разных местах формы).
- На поля можно назначить дополнительные обработчики, задающие более хитрое поведение. Сами обработчики пишутся в коде, по возможности — максимально абстрагированно от конкретного поля. Назначаться они при этом должны не из кода, а из интерфейса конфигурации модели. На этих дополнительных обработчиках должно работать всё! Примеры:
- Платформа, ОС: функции угадывания значения по умолчанию на основе заголовков запроса.
- Статус: есть ограничения переходов из состояния в состояние (workflow). Возможно, его нужно попытаться вынести в базовые настройки модели.
- CC: специальное поведение при клонировании, смене Assignee и QA (старые добавляются в CC), специальное «значение по умолчанию», зависящее от компонента. Возможно, зависимые значения по умолчанию стоит как-то протащить в общее ядро, но это чуть более тонкий момент, чем всё остальное.
- Keywords/теги: автосоздание новых значений.
- История хранится централизованно для всех объектов.
- Общий механизм рассылки изменений по почте для всех объектов каким-либо образом «связанным» пользователям. Настройки уведомлений на уровнях: событие (изменено значение поля, добавлена сущность) и отношение (собственно связь).
- Поиск: адаптировать сильно прокачанный движок поиска из Bugzilla4Intranet. Адаптировать долго не придётся, потому что с точки зрения read-only все типы полей останутся, по сути, те же самые. С другой стороны, его нужно обобщить, так что кое-что сделать всё-таки будет нужно. Но зато в итоге получится супер-инструмент — система выборок, которая отлично хавает большие базы, сложные и произвольные структуры запросов и не давится :) (доказано Bugzilla4Intranet)
- Права доступа: Нужна опять-таки общая схема для всех объектов, с одной стороны, простая для вычисления системой, а с другой стороны, дающая достаточную гибкость разных настроек. По всей видимости, нужны с одной стороны опять-таки «связанные» пользователи, а с другой стороны — роли. Причём, пользователи могут быть «связанные» через какое-то поле — например, человек может быть связан с багом, потому что прописан как Global Watcher для продукта этого бага. Роли могут набираться из действий над полями различных объектов и права на просмотр объектов. Возможно, нужно давать возможность разграничивать доступ на просмотр к разным полям — например, в Bugzilla только группа time-tracker’ов может посмотреть информацию о рабочем времени.
Таким образом наш трекер превратится, по сути, в модульное приложение, построенное вокруг очень прокачанного автоинтерфейса полей и объектов. Естественно, это уже не Bugzilla ни разу, но зато чем-то похоже на Roundup — «конструктор трекеров». Однако и с ним различий много — roundup не умеет зависимых селект-полей, модель задаётся в коде, права доступа слабые, поиск слабый.
Обновление модели
Обновление базы багзильское (тупая последовательность операций):
- (+) Очевидный порядок обновлений, нет проблем с их зависимостями друг от друга (новые просто дописываются в конец, порядок всегда правильный)
- (-) Не проверяется, корректна ли схема БД после обновлений
- (-) Обновления задаются именно для SQL БД, а не для метамодели
- (-) Не очень красивая портянка в функции обновления БД
Обновление базы наше:
- AddType -> RenameFields -> AddFields -> ChangeFields -> DropFields
- ChangeFields с помощью функций обновления
- (???) Самый интересный вопрос - как сделать функции обновления не на SQL, в условиях когда модель в неконсистентном и вообще не знает, в каком состоянии?
- После каждого шага запуск хука
- Переименования задаются декларативно
- Возможность Dry Run, просмотра и проверки последовательности обновлений
- Зависимости обновлений в рамках каждого шага можно задать декларативно (хотя ситуация редкая)
- А может, просто стоит задавать их в ассоциативном массиве по порядку
- Ещё может быть, что обновление одного типа зависит от обновления другого (причём это уже более частая ситуация)
Модель
Получается, что ядро модели состоит из следующих таблиц:
- Типы объектов
- Название типа
- Дополнительное поведение типа
- Поля
- Ссылка на объект
- ID поля
- Название поля
- Тип поля
- Nullable? Т.е. разрешено ли пустое значение
- Поле этого же объекта, контролирующее видимость данного (для не-select полей)
- Связи поля (для select-полей)
- Дополнительное поведение поля
- Контроль видимости полей
- Ссылка на поле
- ID объекта, для которого оно видно
- Транзакции (группы изменений)
- Момент времени
- Изменивший пользователь
- История изменений
- Ссылка на транзакцию
- Тип объекта
- Ссылка на объект
- Ссылка на поле (кроме добавления объекта)
- Старое значение
- Новое значение
- Один неудаляемый тип — пользователи (их поля, тем не менее, можно менять)
- Связи объектов с пользователями
- ID связи
- Название связи
- Ссылка на объект
- Цепочка свойств, заканчивающаяся объектом «пользователь»
- Пользовательские настройки оповещений
- Ссылка на пользователя (либо пустая для настроек по умолчанию)
- Ссылка на связь
- Тип события: добавление/удаление/изменение
- Ссылка на поле объекта (может быть пустая)
- Роли (или группы, что примерно то же самое)
- Включаемые роли
- Включаемые разрешения
- Разрешения (из которых состоят роли)
- Ссылка на связь
- Тип разрешения: просмотр/создание/удаление/изменение
- Ссылка на поле объекта (пустая = весь объект)
- Ссылка на значение поля (пустая = любое)
Типы полей
Тип | Параметры | Представления |
---|---|---|
Строка | Длина | Input, textarea, rich edit |
Логический | Флажок | |
Числовой | Точность (M.N) | Input |
Дата и/или время | Дата? Время? | Поле со всплывающим календарём, просто календарь, просто поле |
Файл | Поле загрузки файла | |
Single-select | Тип объекта | Радиобатон, HTML-селект |
Multi-select | Тип объекта | HTML-мультиселект, флажки, комбо-бокс |
Текущее состояние
Базовые поля (то, чего не быть логически не может):
- Объект, баг, пользователь, группа, комментарий к багу.
- Продукт имеет специальный смысл — разграничение прав. Поэтому он тоже обязателен.
У каждого поля есть:
- Тип
- Значение по умолчанию
- Вид показа в интерфейсе (по умолчанию?)
- Копируется ли значение атрибута при клонировании
- Показывается ли атрибут в форме создания
- Ссылка на контролирующий атрибут того же объекта, что и этот, и на его значения
- Если выбрано, означает, что атрибут показывается, только если другой атрибут той же сущности, которой принадлежит этот, имеет одно из заданных значений
Типы атрибутов:
- Строка
- Boolean
- Десятичное число
- Дата
- Время
- Дата+время
- Файл (вложение)
- Single-Select → ссылка на сущность (то есть «многие к 1»)
- Multi-Select → ссылка на несколько сущностей одного типа (то есть «многие ко многим»)
- Два способа показа — поле со списком (комбобокс), или мультиселект
- Список тегов, с автодобавлением значений
Существующие поля
Поля багов
Поля багов перечислены ниже. Жирное «да» в колонке «можно отключить» означает, что отключать можно уже сейчас (скорее всего, через параметры типа usevotes и т. п.). Нежирное «да» в колонках «можно отключить» и «можно менять тип» означают, что чисто теоретически логика работы Bugzilla это позволяет.
поле | тип | можно отключить? | можно менять тип? | примечания |
---|---|---|---|---|
short_desc | строка | нет | нет | |
classification | single-select | да | нет | |
product | single-select | да | нет | контролируется classification (или никем), у поля есть привязка к правам пользователя |
component | single-select | да | нет | контролируется product |
version | single-select | да | да | контролируется product, если тип = single-select. значение по умолчанию контролируется component |
rep_platform | single-select | да | да | специальная функция «угадывания» дефолтного значения |
bug_file_loc | строка | да | да | |
op_sys | single-select | да | да | специальная функция «угадывания» дефолтного значения |
bug_status | single-select | нет | нет | есть функция валидации (Bug Status Workflow) |
resolution | single-select | да | нет | у атрибута есть контролирующая видимость сущность (показывается только при bug_status.closed=1) |
status_whiteboard | строка | да | да | |
keywords | multi-select | да | да | показ в виде списка |
bug_severity | single-select | да | нет | |
priority | single-select | да | да | есть желание сделать decimal |
assigned_to | single-select | нет | нет | ссылка на пользователя. значение по умолчанию контролируется component |
reporter | single-select | нет | нет | ссылка на пользователя |
qa_contact | single-select | да | нет | ссылка на пользователя. значение по умолчанию контролируется component |
votes | decimal(,0) | да | нет | |
cc | multi-select | да | нет | ссылка на пользователей. значение по умолчанию контролируется component |
dependson | multi-select | да | нет | ссылка на баги. показ в виде списка |
blocked | multi-select | да | нет | ссылка на баги. показ в виде списка |
target_milestone | single-select | да | да | контролируется product, если тип = single-select |
see_also | multi-select | да | да | ссылка на баги. показ в виде списка (багов), если тип = single-select |
alias | строка | да | да | |
reporter_accessible | boolean | нет | нет | |
cclist_accessible | boolean | нет | нет | |
estimated_time | время | да | нет | |
remaining_time | время | да | нет | |
deadline | дата | да | нет | |
creation_ts | дата+время | нет | нет | |
delta_ts | дата+время | нет | нет | |
cf_agreement | single-select | да | да | контролируется product |
*** нет в fielddescs *** | ||||
lastdiffed | дата+время | нет | нет | скрыто в интерфейсе |
attachments | multi-select | нет | нет | 1 ко многим |
longdescs | multi-select | нет | нет | 1 ко многим |
flags | multi-select | да | нет | 1 ко многим |
Примечания:
- Все поля-ссылки на пользователей показываются в виде строки либо в виде combo-box’а, и у них есть функция валидации — она угадывает юзеров по некорректным именам.
Логически минимальный набор полей
Совершенно точно, никогда и ни при каких условиях у бага не могут отсутствовать поля:
- ID
- Заголовок
- История => reporter, время создания (creation_ts), время изменения (delta_ts), время оповещения по почте (lastdiffed)
- Комментарии
Без этого никакой «баг» смысла не имеет ни в одном баг-трекере.
Устаревшие поля
Устаревшие поля / поля, которые ХЗ зачем нужны в таблице полей багов:
- assignee_accessible
- qacontact_accessible
- longdesc
- commenter
- longdescs.isprivate
- content
- bug_group
- flagtypes.name
- requestees.login_name
- setters.login_name
Вычисляемые поля
Вычисляемые поля багов:
work_time | Сумма work_time от связанных longdescs |
---|---|
percentage_complete | (Сумма work_time от dependson)/(Сумма estimated_time от dependson) |
owner_idle_time | Текущая дата минус MAX(дата последнего коммента от Assignee, дата последней активности от Assignee) |
days_elapsed | Текущая дата минус delta_ts |
everconfirmed | Менялся ли статус хоть раз на != UNCONFIRMED |
Поля вложений
submitter | single-select, показ в виде select’а или строки, есть функция валидации (угадывания юзера по некорректному имени) |
---|---|
description | строка |
filename | строка |
mimetype | строка |
ispatch | boolean |
isobsolete | boolean |
isprivate | boolean |
isurl | boolean |
thedata | потенциально строка, а вообще-то обычно NULL, так как данные хранятся в локальных файлах |
Поля компонентов
поле | тип | можно отключить? | можно менять тип? | примечания |
---|---|---|---|---|
name | строка | нет | нет | |
initialowner | single-select | да | нет | ссылка на пользователя |
initialqacontact | single-select | да | нет | ссылка на пользователя |
initialcc | multi-select | да | нет | ссылка на пользователей |
default_version | single-select | да | нет | ссылка на версию |
description | строка | да | да | |
product_id | single-select | нет | нет | |
wiki_url | строка | да | нет | |
is_active | boolean | да | нет |
Из чего состоит багзилла?
С внешней точки зрения
Крупные блоки функционала в Bugzilla с точки зрения пользователя:
- Создание, просмотр, изменение багов, история по багу
- Форматирование комментариев
- Создание, просмотр, изменение вложений
- Поиск багов, форма поиска
- Графики одни, графики другие, Summarize Time
- Исходящая почта
- Входящая почта
- Запросы флагов
- Напоминания (whining)
- Регистрация, изменение, раздача групп пользователям
- Пользовательские настройки
- XML-импорт (в полудохлом виде)
- Web-сервисы (XML-RPC, JSON-RPC)
- Sanity Check
- Графы и деревья зависимостей
- Голосование за баги
Наши крупные фичи
- SCRUM-карточки
- RSS-лента активности
- XML-Simple Web-сервисы
- Проверки корректности
- Excel-импорт
- Информер
- Глобальная авторизация
- Today Worktime, Super Worktime
Плюс вагон и маленькая тележка мелочи.
Страница создания бага (enter_bug.cgi)
Текущая логика страницы создания бага:
- выбор classification, если она включена
- classification выбрана → выбор product, если он не вообще один
- тот же выбор продукта/классификации при клонировании багов
- продукт выбран → форма создания бага
- показ корректных списков возможных значений полей:
- типы флагов в зависимости от компонента
- cf_agreement в зависимости от продукта
- списки пользователей, относящихся к багу в combo-box’ы
- опциональный запрет на ввод приоритета на основе конфигурации (letsubmitterchoosepriority)
- список флажков — ограничителей доступа группами
- значения полей по умолчанию:
- которые совсем по умолчанию
- угадывание op_sys и rep_platform на основе заголовков запроса
- версия, qa_contact, assigned_to, cc по умолчанию для компонента
- хитрая логика для изменения списков cc при выборе компонентов
- assigned_to=ты при выборе статуса ASSIGNED
- показ поля resolution при выборе закрытого статуса
- версия из cookies
- загруженные из шаблона ввода бага
- загруженные из клонированного бага
- ссылка на старый аттач в описании нового клонированного бага
- хитрая логика для CC при клонировании багов
- напоминания о вводе времени
- предпросмотр комментариев
- добавление ссылки на старый аттач для клонированного из коммента бага
- переключатель Show Expert Fields
- Submit по Ctrl-Enter
Обработчик создания бага (post_bug.cgi)
- Редирект на enter_bug.cgi если форма не заполнена
- Проверка, не был ли уже использован этот token для постановки другого бага?
- Вывод страницы с URL-шаблоном постановки бага, если попросили
- Заполнение описания по шаблону, если использовался спецвид формы (например create_guided)
- Отправка куки VERSION
- Начало/конец транзакции в БД
- Постановка собственно бага (Bug::create)
- Постановка вложения сразу при создании бага
- Постановка флагов на вложение
- Постановка флагов на баг
- Рассылка почты по багу, по его зависимостям
- Вывод сообщения о том, что баг поставлен, о том, что CC-список обрезан по группе
Обработчик изменения бага (process_bug.cgi)
- Начало/конец транзакции в БД
- SELECT FOR UPDATE багов
- Удаление значений полей, равных dontchange (используется в групповом редактировании)
- Угадывание юзеров по части логина/имени
- Проверка коллизии по delta_ts, вывод только действительно изменённых полей в форму подтверждения
- Проверка token формы
- Загрузка следующего бага из списка ДО обновления текущего (O_O)
- Проверка прав редактирования по всем багам
- Установка значения продукта до всех остальных полей
- Установка новых групп до остальных изменений, когда включён strict_isolation
- Установка/изменение флагов
- Установка зависимостей бага
- Установка ключевых слов
- Установка остальных полей
- Установка некоторых значений только для обновлений отдельных багов (alias, cclist_accessible, reporter_accessible, isprivate на комментах)
- БОльшая часть логики обновления поля CC
- Вызов функции проверки strict_isolation
- Перемещение багов (MOVE) — полуживое, хз как работает
- И после всего этого — ещё изменения, status, resolution, dup_id
- Теперь всё это ещё незакоммичено, вызов реальных обновлений из Bug.pm
- Отправка почты по зависимостям, если статус поменялся с открытого на закрытый
- Обрезание CC-списка по группе (наше)
- Сообщение, если очищено remaining_time
- Удаление голосов за баг, если переместили в другой продукт, и проверка голосо-подтвеждённости бага
- Отправка почты CC, Assignee, Reporter’у, QA, старым Assignee, QA и CC
- Отправка почты по багу, дубликатом которого был помечен данный
- Добавление нескольких вложений (наше)
- Отправка почты по флагам, через отдельный механизм сбоку
- Редирект (наше) или показ следующего/того же/никакого бага
- Не показывает ничего, если USAGE_MODE_EMAIL
Список/поиск багов (buglist.cgi)
- SuperWorkTime (наше доработко)
- Редирект на форму поиска для пустого запроса
- Редирект на форму поиска с добавленными пустыми полями, если на форме поиска жмут Add/Remove поле без JS
- Редирект с POST’енного запроса на GET
- Быстрый поиск
- Посыл на хрен, если content пуст при включённом параметре specific_search_allow_empty_words
- Обратная совместимость: format=rdf -> ctype=rdf, ctype=rss -> ctype=atom
- ctype=js слать в хрен
- Поддержка server-push
- regetlastlist — открытие последнего просмотренного списка багов (берётся из куки)
- Удаление колонки relevance из списка колонок, если юзер не просит полнотекстовый поиск
- В buglist.cgi почему-то тусуются функции InsertNamedQuery, LookupSeries, GetQuip, GetGroups
- Генерация имени файла, если попросили список не в html-формате
- Выполнение запросов поиска
- Сохранение и удаление сохранённых запросов из БД
- Запуск series
- Если сохранённый запрос не говорил нам свой формат, решаем что advanced
- Вкуривание списка колонок (длинное, тварь)
- Определение порядка сортировки
- Подсчёт сумм значений полей таймтрекинга
- Проверка доступа к багам и установка значения в implied или manual (х.з зачем нужно)
- Массовое редактирование багов, в частности сборка пересечений доступных значений полей
- Кодировка CSV (наше доработко)
Система прав
Какие в Bugzilla есть права / ограничения доступа?
- Права доступа к продуктам
- MANDATORY / SHOWN / DEFAULT / NA
- Entry
- Canedit
- Editcomponents
- Canconfirm
- Editbugs
- Private комментарии — видны только инсайдер-группе
- Информация о таймтрекинге — видна только группе, списывающей время
- reporter_accessible, cclist_accessible на отдельных багах
- Опциональные группы на отдельных багах
- Права на правку отдельных групп
- Права editclassifications, editcomponents, editfields, editkeywords, editusers
Настройки оповещений о багах
Отношения:
- Assignee, QA, Reporter, CC
- Requestee или Setter флага (реально в Bugzilla прикручено сильно сбоку)
- По идее — также создатель аттачмента, коммента (если разрешать править)
- Watcher указанного выше
- Global Watcher
События:
- Добавлен/удалён из указанного выше
- Изменено одно из полей бага (м.б отдельные настройки, м.б вместе)
- Баг / блокирующий баг меняет статус с закрытого на открытый или обратно
- «Но кроме» UNCONFIRMED
- «Но кроме» своих изменений
Что не так?
Что в Bugzilla не так? Что нужно поменять, чтобы она перестала быть говном?
Да, я знаю, что почти всё, но дело не в этом — дело в том, что создавать систему «от противного» — есть хороший тон, ведущий к прогрессу.
Ядро
Самое жирное «не так» в Bugzilla — это слабость ядра. Если бы ядро было прокачанным, как в начале статьи, оно бы заменило:
- Custom Fields, то есть, управление полями багов.
- Отключение стандартных полей типа OS, Hardware.
- Добавление спецполей в продукты, компоненты и т. д. — сейчас это делается в коде.
- Версионирование всех объектов. История бы хранилась унифицированно. Не было бы отдельно таблиц bugs_activity и longdescs, соответственно не было бы и тормозов при проверке «Only bugs changed between…» либо комментарии бы дублировались в bugs_activity (логичнее)
- Отправка почты, которая сейчас отправляется через 2 разных места.
- Простые интерфейсы типа CRUD (Create/Read/Update/Delete), сейчас созданные непонятно каким копипастом. В основном имеется ввиду админка.
- Система прав стала бы и проще (по сравнению с хрен-пойми-системой Mandatory/Default/Shown/NA), и имела бы больше возможностей.
- Валидаторы и подсказки значений.
- Корректная валидация зависимостей полей друг от друга.
- Часть SQL-запросов, написанных ручками в коде.
- Вся логика постановки/обновления багов из process_bug и post_bug, дублированная сейчас в обработке входящих e-mailов и Excel-импорте
- Даже Excel- и XML-импорт, причём импортировать можно было бы вообще всё что угодно.
Появились бы дополнительные возможности:
- Создание новых объектов типа SCRUM карточек.
- Изменение типов стандартных полей типа целочисленных приоритетов.
- Можно было бы прикрутить статистику по любым объектам, причём с Time Machine, то есть просмотром статистики за любой прошедший момент времени. :)
Внешности
- Большая часть интерфейсов нуждается в полной переделке. Например:
- На форме бага «Show Advanced Fields» должно быть сделано отдельной группкой полей (fieldset), а не скрытием полей прямо посреди формы в разных местах (пугает).
- Страница настройки прав продукта — мегастрёмная. Таблица с группами там на хрен не нужна никому вообще.
- Частично относится к ядру, но — интерфейс редактирования «контроля значений» кастом-полей это сейчас полная жесть — например, нельзя посмотреть список значений кастом поля для конкретного продукта (от которого зависят наборы значений).
- Историю изменений бага показывать вперемешку с комментариями к багу (а-ля Trac). Туда же можно заинтегрировать и замешать коммиты из системы контроля версий.
- Добавить ленту обновлений по багам, поиск «последних багов», что-то типа форум-функциональности.
- Возможно, добавить Grid View с возможностью массовых обновлений в поиске.
- Отрефакторить кучу действий, связанных с поиском, расположенных под списком багов.
- Keywords переделать в «теги», то есть, сделать, чтобы они сами заводились новые.
-
Заменить YUI на jQueryв Bugzilla4Intranet уже, форму поиска сгруппировать (но не так, как в 4.0), сделать почти все фильтры добавляемыми, добавляемыми через JS, чтобы не перезагружалась страница каждый раз - Документацию «насытить» в вики, POD-документацию по коду туда же.
Кишки, кроме ядра
- Добавить глобальный объект статуса, в который сохранять почту, которую нужно отправить, и сообщения, которые сейчас руками сохраняются в сессию.
- Использовать не CGI, а хеши параметров запроса, это улучшает и производительность, и переносимость, и спасает от кучи глюков, так как например, $cgi->param может вернуть как список, так и скаляр
- Использовать не кучу CGI-скриптов, а несколько (мало) точек входа и классы, всю мохнатую логику перенести в них. Не использовать модуль CGI.pm вообще (!), потому что он прости господи даже без use strict написан и порождает некоторые глюки сам по себе. В крайней форме точки доступа — это один index.cgi, позволяющий работать через CGI, один server.fcgi (FastCGI), один модуль для апача, и м.б. один для HTTP::Server::Simple. Ибо по сути, интерфейс «запроса» тривиален и не требует никакого бешеного CGI.
- Убрать ВСЕ строки (terms и т. п.) и описания ошибок из шаблонов и «длинного if’а», добавить отдельный уровень «локализации» / «таблицы строк», и переместить всё это в него. Потенциально также переместить туда же вообще все строки/тексты из шаблонов, для лёгкой локализации.
- Обязательно оставить совместимость с PostgreSQL, но генерилка запросов не должна на это рассчитывать и должна работать оптимальнее, чем сейчас, например, в смысле дурацких подзапросов assigned_to=(select id from profiles where login_name=?) и т. п.
- Желательно заменить Template::Toolkit на что-нибудь, хотя бы даже на моё поделие VMX::Template, чтобы не общаться с этим тормозом. Но как МИНИМУМ, даже если не заменять — убрать ВСЮ обратную связь с БД из шаблонов, ибо именно она убивает производительность в первую очередь! Ну ладно, не в первую, а во вторую, после дурацкого движка поиска. Хотя это и будет уже не MVC, а MVP :)