BugzillaORM — различия между версиями

м
м (Обновление модели)
 
(не показано 30 промежуточных версий этого же участника)
Строка 1: Строка 1:
В Bugzilla половина кода в шаблонах, половина на основе полу-ORM’а Bugzilla::Object. Большая часть - говнокод. С одной стороны - ORM бы туда, было бы классно, НО! ORM мало, и нужен не он! Все (существующие) ORM-движки - это просто объектный интерфейс к базе данных. А нужно некое объектное ядро, которое бы позволяло создавать свои объекты, с полями различных типов, в том числе и ссылающимися на другие такие же объекты, с возможностью приписывания специальных особенностей полю, с общим механизмом хранения истории и с автоматическим базовым CRUD-интерфейсом.
+
[[Категория:Разработка]]
 +
В Bugzilla половина кода в шаблонах, половина на основе полу-ORM’а Bugzilla::Object. Большая часть — говнокод. С одной стороны — ORM бы туда, было бы классно, НО! ORM мало, и нужен не он! Почти все существующие ORM-движки (кроме разве что [https://docs.djangoproject.com/en/dev/topics/db/models/ Django Models]) — это просто объектный интерфейс к базе данных. А нужно некое объектное ядро, которое бы позволяло создавать свои объекты, с полями различных типов, в том числе и ссылающимися на другие объекты, с возможностью приписывания специальных особенностей полям, с общими механизмами хранения истории, рассылки уведомлений, системой прав и с автоматическим базовым CRUD-интерфейсом.
 +
 
 +
== Идеи по созданию объектного ядра ==
 +
 
 +
=== Объекты в Bugzilla ===
 +
 
 +
* баг
 +
* классификация, продукт, компонент
 +
* тег (ключевое слово / keyword), milestone, версия, статус бага, agreement (пример кастомного поля)
 +
* вложение, комментарий, флаг, тип флага
 +
* пользователь, группа
 +
* если таки будет ядро — ещё появляется метакласс сущности, объекты которого описывают типы сущностей
  
 
<graph>
 
<graph>
Строка 19: Строка 31:
 
</graph>
 
</graph>
  
Есть сущности:
+
Причём, понятное дело, если баг принадлежит к некоторому продукту (через компонент), то и его версия, milestone, agreement должны принадлежать к тому же продукту. Сейчас в Bugzilla это реализуется так — для каждой сущности, связанной с багом, в баге есть «поле», а для ограничения значений полей поля делаются «зависимыми» от других полей. Из-за этого там куча костылей и, по сути, повесить зависимость на отличное от поля «продукт» поле невозможно.
* баг
+
* классификация, продукт, компонент
+
* тег (ключевое слово / keyword), milestone, версия, статус бага, agreement (кастомное поле!)
+
* вложение, комментарий, флаг, тип флага
+
* пользователь, группа
+
* как ни странно, «сущность» — «метакласс» (класс сущности)
+
  
У сущностей есть:
+
=== Минусы текущей реализации ===
* ID — первичный ключ
+
* атрибуты
+
* ссылка на контролирующее поле и значения <br /> то есть если другая сущность ссылается на эту, другим полем она должна ссылаться и на контролирующую
+
* способ преобразования в строку
+
* ''Возможно, права доступа к сущности — привязка действий над сущностью (просмотр, правка, возможно, другие) к группам пользователей. Возможно, не нужно это сюда пихать.''
+
  
У каждого атрибута есть:
+
Чем плоха текущая багзильная реализация этого «добра»?
 +
 
 +
Очень просто: '''почти ни хрена не настраивается''' - нельзя ни добавить свои возможности, ни отрубить ненужные встроенные. Ибо всё жёстко и криво (хардкод). А ещё:
 +
* История хранится только для багов, но не для остальных объектов.
 +
* Шаблоны переусложнены.
 +
* Нет "объектов", есть «значения полей», соответсвенно, им не добавишь атрибутов и не навесишь логики.
 +
 
 +
* Значения кастом полей в таблице багов хранятся не ссылками по 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}} Строка
 
* {{ok}} Строка
** E-mail адрес — особенности: опционально скрывается ради антиспама, может иметь настройки уведомлений
 
 
* Boolean
 
* Boolean
* {{ok}} Decimal
+
* {{ok}} Десятичное число
 
* Дата
 
* Дата
 
* Время
 
* Время
 
* {{ok}} Дата+время
 
* {{ok}} Дата+время
 +
* Файл (вложение)
 
* Single-Select &rarr; ссылка на сущность (то есть «многие к 1»)
 
* Single-Select &rarr; ссылка на сущность (то есть «многие к 1»)
** ''Необязательный вариант синглселекта — «1 к 1».''
 
** {{ok}} существует в частичном виде — без выбора желаемой сущности
 
 
* Multi-Select &rarr; ссылка на несколько сущностей одного типа (то есть «многие ко многим»)
 
* Multi-Select &rarr; ссылка на несколько сущностей одного типа (то есть «многие ко многим»)
** Вариант мультиселекта — «список подчинённых» (то есть 1 ко многим). Например, список аттачментов бага, список комментов к багу.
+
** Два способа показа — поле со списком (комбобокс), или мультиселект
** {{ok}} существует в частичном виде — без выбора желаемой сущности
+
* Список тегов, с автодобавлением значений
* Файл (вложение).
+
 
 +
== Существующие поля ==
  
Email-уведомления в общем виде задаются как уведомление на поле типа email, вытаскиваемое по цепочке из сущности (например bug.product.product_watcher.email) при изменении заданных атрибутов сущности.
+
=== Поля багов ===
  
Поля багов перечислены ниже. Жирное «да» в колонке «можно отключить» означает, что отключать можно уже сейчас (скорее всего, через параметры типа usevotes и т. п.). Нежирное «да» в колонках «можно отключить» и «можно менять тип» означают, что чисто теоретически логика работы Bugzilla это позволяет.
+
Поля багов перечислены ниже. Жирное «да» в колонке «можно отключить» означает, что отключать можно уже сейчас (скорее всего, через параметры типа usevotes и т. п.). Нежирное «да» в колонках «можно отключить» и «можно менять тип» означают, что чисто теоретически логика работы Bugzilla это позволяет.
 
<tab sep=bar class=simpletable head=topleft>
 
<tab sep=bar class=simpletable head=topleft>
 
поле | тип | можно отключить? | можно менять тип? | примечания
 
поле | тип | можно отключить? | можно менять тип? | примечания
Строка 106: Строка 222:
  
 
Примечания:
 
Примечания:
* Все поля-ссылки на пользователей показываются в виде строки либо в виде combo-box’а, и у них есть функция валидации — она угадывает юзеров по некорректным именам.
+
* Все поля-ссылки на пользователей показываются в виде строки либо в виде combo-box’а, и у них есть функция валидации — она угадывает юзеров по некорректным именам.
 +
 
 +
==== Логически минимальный набор полей ====
 +
 
 +
Совершенно точно, никогда и ни при каких условиях у бага не могут отсутствовать поля:
 +
* ID
 +
* Заголовок
 +
* История => reporter, время создания (creation_ts), время изменения (delta_ts), время оповещения по почте (lastdiffed)
 +
* Комментарии
 +
Без этого никакой «баг» смысла не имеет ни в одном баг-трекере.
 +
 
 +
==== Устаревшие поля ====
  
 
Устаревшие поля / поля, которые ХЗ зачем нужны в таблице полей багов:
 
Устаревшие поля / поля, которые ХЗ зачем нужны в таблице полей багов:
Строка 119: Строка 246:
 
* requestees.login_name
 
* requestees.login_name
 
* setters.login_name
 
* setters.login_name
 +
 +
==== Вычисляемые поля ====
  
 
Вычисляемые поля багов:
 
Вычисляемые поля багов:
Строка 129: Строка 258:
 
</tab>
 
</tab>
  
Поля вложений:
+
=== Поля вложений ===
 +
 
 
<tab sep=bar class=simpletable head=left>
 
<tab sep=bar class=simpletable head=left>
 
submitter | single-select, показ в виде select’а или строки, есть функция валидации (угадывания юзера по некорректному имени)
 
submitter | single-select, показ в виде select’а или строки, есть функция валидации (угадывания юзера по некорректному имени)
Строка 142: Строка 272:
 
</tab>
 
</tab>
  
Поля компонентов:
+
=== Поля компонентов ===
  
 
<tab sep=bar class=simpletable head=top>
 
<tab sep=bar class=simpletable head=top>
Строка 157: Строка 287:
 
</tab>
 
</tab>
  
Что ушло бы в ORM?
+
== Из чего состоит багзилла? ==
  
* Custom Fields, то есть, управление полями багов.
+
=== С внешней точки зрения ===
* Отключение стандартных полей типа OS, Hardware.
+
* Изменение типов стандартных полей типа целочисленных приоритетов.
+
* Добавление спецполей в продукты, компоненты и т. д. — сейчас это делается в коде.
+
* Версионирование всех объектов. История бы хранилась унифицированно. Не было бы отдельно таблиц bugs_activity и longdescs, соответственно не было бы и тормозов при проверке «Only bugs changed between…»
+
* Простые интерфейсы типа CRUD (Create/Read/Update/Delete), сейчас созданные непонятно каким копипастом. В основном имеется ввиду админка.
+
* Права на редактирование объектов.
+
* Валидаторы и подсказки значений.
+
* Корректная валидация зависимостей полей друг от друга.
+
* Часть SQL-запросов, написанных ручками в коде.
+
* Создание новых объектов типа SCRUM карточек.
+
* Мохнатая логика автоматической постановки/обновления багов из обработки входящих e-mailов и Excel-импорта
+
  
* Можно было бы прикрутить статистику по любым объектам, причём с Time Machine, то есть просмотром статистики за любой прошедший момент времени. :)
+
Крупные блоки функционала в 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) ===
  
 
Текущая логика страницы создания бага:
 
Текущая логика страницы создания бага:
Строка 185: Строка 336:
 
** списки пользователей, относящихся к багу в combo-box’ы
 
** списки пользователей, относящихся к багу в combo-box’ы
 
** опциональный запрет на ввод приоритета на основе конфигурации (letsubmitterchoosepriority)
 
** опциональный запрет на ввод приоритета на основе конфигурации (letsubmitterchoosepriority)
** список флажков — ограничителей доступа группами
+
** список флажков — ограничителей доступа группами
 
* значения полей по умолчанию:
 
* значения полей по умолчанию:
 
** которые совсем по умолчанию
 
** которые совсем по умолчанию
Строка 200: Строка 351:
 
* напоминания о вводе времени
 
* напоминания о вводе времени
 
* предпросмотр комментариев
 
* предпросмотр комментариев
* постановка вложения сразу при создании бага
+
* добавление ссылки на старый аттач для клонированного из коммента бага
 
* переключатель Show Expert Fields
 
* переключатель Show Expert Fields
 
* Submit по Ctrl-Enter
 
* Submit по Ctrl-Enter
  
[[Категория:Bugzilla]]
+
=== Обработчик создания бага (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 :)

Do you want to try some new features? By joining the beta, you will get access to experimental features, at the risk of encountering bugs and issues.

Ок Нет, спасибо

Текущая версия на 12:09, 24 июля 2012

В Bugzilla половина кода в шаблонах, половина на основе полу-ORM’а Bugzilla::Object. Большая часть — говнокод. С одной стороны — ORM бы туда, было бы классно, НО! ORM мало, и нужен не он! Почти все существующие ORM-движки (кроме разве что Django Models) — это просто объектный интерфейс к базе данных. А нужно некое объектное ядро, которое бы позволяло создавать свои объекты, с полями различных типов, в том числе и ссылающимися на другие объекты, с возможностью приписывания специальных особенностей полям, с общими механизмами хранения истории, рассылки уведомлений, системой прав и с автоматическим базовым CRUD-интерфейсом.

Идеи по созданию объектного ядра

Объекты в Bugzilla

  • баг
  • классификация, продукт, компонент
  • тег (ключевое слово / keyword), milestone, версия, статус бага, agreement (пример кастомного поля)
  • вложение, комментарий, флаг, тип флага
  • пользователь, группа
  • если таки будет ядро — ещё появляется метакласс сущности, объекты которого описывают типы сущностей

[svg]

Причём, понятное дело, если баг принадлежит к некоторому продукту (через компонент), то и его версия, 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-мультиселект, флажки, комбо-бокс

Текущее состояние

Базовые поля (то, чего не быть логически не может):

  • Объект, баг, пользователь, группа, комментарий к багу.
  • Продукт имеет специальный смысл — разграничение прав. Поэтому он тоже обязателен.

У каждого поля есть:

  • Тип
  • Значение по умолчанию
  • Вид показа в интерфейсе (по умолчанию?)
  • Копируется ли значение атрибута при клонировании
  • Показывается ли атрибут в форме создания
  • Ссылка на контролирующий атрибут того же объекта, что и этот, и на его значения
    Если выбрано, означает, что атрибут показывается, только если другой атрибут той же сущности, которой принадлежит этот, имеет одно из заданных значений

Типы атрибутов:

  • Ok16.png Строка
  • Boolean
  • Ok16.png Десятичное число
  • Дата
  • Время
  • Ok16.png Дата+время
  • Файл (вложение)
  • 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 :)