Redmine на чем написан
Redmine
Redmine — открытое серверное веб-приложение для управления проектами и задачами (в том числе для отслеживания ошибок). Redmine написан на Ruby и представляет собой приложение на основе широко известного веб-фреймворка Ruby on Rails. Распространяется согласно GNU General Public License.
Содержание
Функциональные возможности
Данный продукт предоставляет следующие возможности:
Структура базы данных
Пользователи системы
Пользователи являются одним из центральных понятий предметной области. Модель пользователя является основой для идентификации и аутентификации работающего с системой персонала и клиентов, а также для авторизации их в разных ролях, проектах и т. п.
Роли пользователей определяются гибкой моделью определения прав доступа пользователей. Роли включают в себя набор привилегий, позволяющих разграничивать доступ к различным функциям системы.
Пользователям назначается роль в каждом проекте, в котором он участвует, например «менеджер в проекте по разработке сайта А», «разработчик в проекте по поддержанию интранета компании» или «клиент в проекте по рефакторингу информационной системы компании Б». Пользователь может иметь несколько ролей. Назначение роли для отдельной задачи (issue) в данный момент невозможно.
Проекты
Проект является одним из основных понятий в предметной области систем управления проектами. Благодаря этой сущности возможно организовать совместную работу и планирование нескольких проектов одновременно с разграничением доступа различным пользователям (см. выше). Проекты допускают иерархическую вложенность.
Трекеры
Трекеры являются основной классификацией, по которой сортируются задачи в проекте. Само по себе понятие «трекер» восходит к системам учёта ошибок (англ. Bug tracking tool ), представлявшим каждая в отдельности один проект.
По сути, в «Redmine» трекеры представляют собой аналог подклассов класса «Задача» и являются основой для полиморфизма разного рода задач, позволяя определять для каждого их типа различные поля. Примерами трекеров являются «Улучшение», «Ошибка», «Документирование», «Поддержка»,
Задачи
Задачи являются центральным понятием всей системы, описывающим некую задачу, которую необходимо выполнить. У каждой задачи в обязательном порядке есть описание и автор, в обязательном порядке задача привязана к трекеру.
Каждая задача имеет статус. Статусы представляют собой отдельную сущность с возможностью определения прав на назначение статуса для различных ролей (например, статус «отклонен» может присвоить только менеджер) или определение актуальности задачи (например, «открыт», «назначен» — актуальные, а «закрыт», «отклонен» — нет).
Для каждого проекта отдельно определяются набор этапов разработки и набор категорий задач. Среди других полей интересны также «оцененное время», служащее основой для построения управленческих диаграмм, а также поле выбора наблюдателей за задачей (см. «Получение уведомлений»). К задачам имеется возможность прикреплять файлы (имеется отдельная сущность «Приложение»).
Значения других перечислимых свойств (например, приоритетность) хранятся в отдельной общей таблице.
Отслеживание изменения статуса задач
За отслеживание изменений параметров задач пользователями в системе отвечают две сущности: «Запись журнала изменений» и «Измененный параметр». Запись журнала отображает одно действие пользователя по редактированию параметров задачи и/или добавление комментария к ней. То есть служит одновременно инструментом ведения истории задачи и инструментом ведения диалога.
Сущность «Измененный параметр» привязана к отдельной записи журнала и предназначена для хранения старого и нового значения измененного пользователем параметра.
Связи между задачами
Задачи могут быть взаимосвязаны: например, одна задача является подзадачей для другой или предшествовать ей. Эта информация может быть полезна в ходе планирования разработки программы, за её хранение в Redmine отвечает отдельная сущность.
Учет затраченного на проект времени
Система поддерживает учет затраченного времени благодаря сущности «Затраченное время», связанной с пользователями и задачей. Сущность позволяет хранить затраченное время, вид деятельности пользователя (разработка, проектирование, поддержка) и краткий комментарий к работе. Эти данные могут быть использованы, например, для анализа вклада каждого участника в проект или для оценки фактической трудоемкости и стоимости разработки
Привязка репозиториев
Redmine предоставляет возможность интеграции с различными системами контроля версий (репозиториями). Интеграция заключается в отслеживании изменений во внешнем репозитории, их фиксации в базе данных, анализе изменений с целью их привязки к определенным задачам. В инфологической структуре системы за интеграцию с внешними репозиториями отвечают три сущности: «Репозиторий», «Редакция» и «Изменение». «Репозиторий» представляет собой связанную с проектом сущность, хранящую тип подключенного репозитория, его местонахождение и идентификационные данные его пользователя.
«Редакция» является отображением редакции репозитория, и, кроме информационных полей, может быть привязана к конкретной задаче (для этого требуется указать в описании изменений «refs #NUM», где NUM — номер задачи), и к пользователю-автору редакции. Сущность «Изменение» предназначена для хранения списка измененных (добавленных, удаленных, перемещенных, модифицированных) файлов в каждой редакции.
Получение уведомлений
Уведомления пользователей об изменениях, происходящих на сайте, осуществляется с помощью сущности «Наблюдатели», связывающей пользователей с объектами различных классов (проекты, задачи, форумы и др.). В базе данных хранятся также ключи доступа к подписке RSS, позволяющие получать уведомления посредством этой технологии, также уведомления рассылаются с помощью электронной почты.
Некоторые недостатки Redmine
ChiliProject
В результате того, что видение некоторых пользователей относительно проекта отличалось от видения лидера разработчиков, был создан форк Redmine под названием ChiliProject.
См. также
Литература
Ссылки
FlexWiki • WWWiki • Perspective • ScrewTurn Wiki
Clearspace • Atlassian Confluence • JAMWiki • JSPWiki • Kerika • Mindquarry • SnipSnap • Traction TeamPage • XWiki
Kwiki • Noösphere • PodWiki • Socialtext • TWiki • Foswiki • UseModWiki • OddMuseWiki • WikiWikiWeb
CitiWiki • DokuWiki • GetWiki • MediaWiki • PhpWiki • PmWiki • PukiWiki • TigerWiki • TikiWiki • WackoWiki • Wiclear • WikkaWiki
MoinMoin • OghamWiki • PikiPiki • PikiePikie • TamTam • Trac • Zwiki
Instiki • Pimki • Redmine
Полезное
Смотреть что такое «Redmine» в других словарях:
Redmine — Startseite der Redmine Demo Basisdaten Maintainer Jean Philippe Lang Aktuelle Version 1.2.2 ( … Deutsch Wikipedia
RedMine — Aperçu du suivi des demandes dans RedMine … Wikipédia en Français
Redmine — Développeur Jean Philippe Lang Dernière version … Wikipédia en Français
RedMine (logiciel) — RedMine Redmine Développeur Jean Philippe Lang Dernière version … Wikipédia en Français
Comparison of issue-tracking systems — This article is a comparison of issue tracking systems which are notable, including bug tracking systems, help desk and service desk issue tracking systems, and asset management systems. The comparison includes client server application,… … Wikipedia
Gravatar — Logo de Gravatar URL www.gravatar.com Slogan A Globally Recognized Avatar … Wikipédia en Français
Bugzilla — Bugzilla … Википедия
Subversion — У этого термина существуют и другие значения, см. Subversion (игра). Subversion Логотип Subversion Тип централизованная … Википедия
Национальная библиотека им. Н. Э. Баумана
Bauman National Library
Персональные инструменты
Redmine
Внешний вид Redmine похож на Trac, приложение, обладающее похожими функциями.
Redmine написан на Ruby on Rails. Приложение является кросс-платформенным и поддерживает 34 языка.
Содержание
Возможности
Redmine предоставляет следующие возможности:
Распространение
По данным разработчика Redmine, веб-приложение используют более 80 известных компаний. Среди пользователей Redmine есть и Ruby. Redmine является самым популярным планировщиком с открытым кодом.
Структура
Пользователи системы
Пользователи являются одним из центральных понятий предметной области. Модель пользователя является основой для идентификации и аутентификации работающего с системой персонала и клиентов, а также для авторизации их в разных ролях, проектах и т. п.
Роли пользователей определяются гибкой моделью определения прав доступа пользователей. Роли включают в себя набор привилегий, позволяющих разграничивать доступ к различным функциям системы.
Пользователям назначается роль в каждом проекте, в котором он участвует, например, «менеджер в проекте по разработке сайта А», «разработчик в проекте по поддержанию интранета компании» или «клиент в проекте по рефакторингу информационной системы компании Б». Пользователь может иметь несколько ролей. Назначение роли для отдельной задачи (issue) в данный момент невозможно.
Проекты
Проект является одним из основных понятий в предметной области систем управления проектами. Благодаря этой сущности возможно организовать совместную работу и планирование нескольких проектов одновременно с разграничением доступа различным пользователям (см. выше). Проекты допускают иерархическую вложенность.
Трекеры
Трекеры являются основной классификацией, по которой сортируются задачи в проекте. Само по себе понятие «трекер» восходит к системам учёта ошибок (англ. Bug tracking tool ), представлявшим каждая в отдельности один проект.
По сути, в «Redmine» трекеры представляют собой аналог подклассов класса «Задача» и являются основой для полиморфизма разного рода задач, позволяя определять для каждого их типа различные поля. Примерами трекеров являются «Улучшение», «Ошибка», «Документирование», «Поддержка»,
Задачи
Задачи являются центральным понятием всей системы, описывающим некую задачу, которую необходимо выполнить. У каждой задачи в обязательном порядке есть описание и автор, в обязательном порядке задача привязана к трекеру.
Каждая задача имеет статус. Статусы представляют собой отдельную сущность с возможностью определения прав на назначение статуса для различных ролей (например, статус «отклонен» может присвоить только менеджер) или определение актуальности задачи (например, «открыт», «назначен» — актуальные, а «закрыт», «отклонен» — нет).
Для каждого проекта отдельно определяются набор этапов разработки и набор категорий задач. Среди других полей интересны также «оцененное время», служащее основой для построения управленческих диаграмм, а также поле выбора наблюдателей за задачей (см. «Получение уведомлений»). К задачам имеется возможность прикреплять файлы (имеется отдельная сущность «Приложение»).
Значения других перечислимых свойств (например, приоритетность) хранятся в отдельной общей таблице.
Отслеживание изменения параметров задач
За отслеживание изменений параметров задач пользователями в системе отвечают две сущности: «Запись журнала изменений» и «Измененный параметр». Запись журнала отображает одно действие пользователя по редактированию параметров задачи и/или добавление комментария к ней. То есть служит одновременно инструментом ведения истории задачи и инструментом ведения диалога.
Сущность «Измененный параметр» привязана к отдельной записи журнала и предназначена для хранения старого и нового значения измененного пользователем параметра.
Связи между задачами
Задачи могут быть взаимосвязаны: например, одна задача является подзадачей для другой или предшествовать ей. Эта информация может быть полезна в ходе планирования разработки программы, за её хранение в Redmine отвечает отдельная сущность.
Учёт затраченного на проект времени
Система поддерживает учёт затраченного времени благодаря сущности «Затраченное время», связанной с пользователями и задачей. Сущность позволяет хранить затраченное время, вид деятельности пользователя (разработка, проектирование, поддержка) и краткий комментарий к работе. Эти данные могут быть использованы, например, для анализа вклада каждого участника в проект или для оценки фактической трудоемкости и стоимости разработки.
Привязка репозиториев
Redmine предоставляет возможность интеграции с различными системами управления версиями (репозиториями). Интеграция заключается в отслеживании изменений во внешнем репозитории, их фиксации в базе данных, анализе изменений с целью их привязки к определенным задачам.
В инфологической структуре системы за интеграцию с внешними репозиториями отвечают три сущности: Репозиторий, Редакция и Изменение.
Получение уведомлений
Уведомления пользователей об изменениях, происходящих на сайте, осуществляется с помощью сущности «Наблюдатели», связывающей пользователей с объектами различных классов (проекты, задачи, форумы и др.). В базе данных хранятся также ключи доступа к подписке RSS, позволяющие получать уведомления посредством этой технологии, также уведомления рассылаются с помощью электронной почты.
Некоторые недостатки Redmine
Установка
Необходимые компоненты для установки Redmine
Шаг 1: Распаковка
Шаг 2: Установка devkit
Шаг 3:Установка необходимых gem’ов
Шаг 4: Настройка Redmine
Шаг 5: Создание БД и первый запуск Redmine
Шаг 6: Создание сервиса для Redmine:
Ответвления
Система управления проектами Redmine + Mercurial на Ubuntu 16.04
По мере увеличения числа вовлечённых в проект людей возникает необходимость как-то более эффективно организовывать и управлять их деятельностью. На начальном этапе для этой цели использовались Google-таблицы, но их возможности ограничены, и появилось желание перейти на новый уровень. Изучение доступных систем управления проектами показало, что из систем с открытым кодом Redmine наиболее продвинутая и по некоторым показателям обгоняет даже проприетарные системы.
Redmine, действительно, обладает большими возможностями: управление несколькими проектами, отслеживание ошибок, интеграция с репозиториями, перекрёстные ссылки на исправленные баги в коммитах и на коммиты в баг-репортах, назначение разных ролей пользователей в каждом проекте и т.д. Однако процедура установки довольна сложна, а для некоторых очень полезных функций требуется небольшая доработка или использование плагинов. Надеюсь, что предлагаемое ниже руководство поможет желающим использовать Redmine в своих проектах.
Компоненты
Система управления проектами Redmine
Система контроля версий Mercurial
Кросс-платформенная распределённая система управления версиями.
Также понадобится
Web-сервер и система управления базами данных. Использованы Mysql и Apache.
Установка
Также использовалась официальная инструкция по установке
Redmine Installation Guide.
Предполагаем что у нас уже есть сервер с предустановленным на нём Ubuntu Server 16.04. Дальнейшие инструкции описывают установку системы управления и вспомогательного ПО.
Итак, начнём. Сначала устанавливаем LAMP server:
Во время установки понадобится ввести пароль root-пользователя базы данных MySQL (не путать с паролем root операционной системы).
Создаём базу данных MySQL и пользователя redmine для работы с ней. Вместо [password] вставляем желаемый пароль пользователя.
Распаковываем Redmine в каталог /usr/share/redmine. Находим подкаталог config и копируем config/database.yml.example в config/database.yml. После этого редактируем файл, для того чтобы установить «production» режим базы данных:
Вводим текст и сохраняем файл (ctrl+x):
Устанавливаем необходимые пакеты:
Теперь можно установить gems, необходимые для Redmine:
Создаём случайный ключ, который Rails будет использовать для шифрования данных в cookie:
Дальше создаём структуру базы данных (выполняем в /usr/share/redmine):
Устанавливаем необходимые права доступа:
При желании можно протестировать установку Redmine с помощью веб-сервера WEBrick:
После запуска WEBrick стартовая страница Redmine должна быть доступна в браузере по адресу http://localhost:3000/
Интеграция с Apache
Добавить символьную ссылку на public каталог Redmine:
Необходимо настроить пользователя Passenger по умолчанию, для этого редактируем файл:
Нужно добавить следующую строчку и сохранить (ctrl+x):
В итоге файл должен выглядеть так:
Далее создать конфигурационный файл redmine.conf для apache:
Добавить следующий текст и сохранить (ctrl+x):
Подключить модули Passenger и Rewite:
Отключить default вебсайт и подключить redmine:
Установить права доступа на /tmp/cache Redmine:
Установка Mercurial
Необходимо установить пакеты:
Создать директорию, в которой будут храниться репозитории проектов:
Теперь мы хотим сделать репозитории доступными по http протоколу. Для этого необходимо создать cgi-скрипт:
Добавить следующий текст и сохранить:
Теперь нужно создать файл hgweb.config:
Добавить следующее содержимое и сохранить:
Установить разрешения для файлов:
Теперь надо создать conf файл для Apache:
Добавить следующее содержимое и сохранить:
Ещё необходимо создать ссылки:
Включить CGI модуль и перезапустить Apache:
Чтобы клонировать репозиторий надо будет выполнить:
Если клонируемый проект не публичный (устанавливается в настройках проекта через веб-интерфейс системы Redmine), то потребуется ввести имя пользователя и пароль.
Авторизация осуществляется по проектам, т.е. доступ будет возможен только для участников проекта (менеджеры и разработчики).
При создании репозитория в веб-интерфейсе Redmine необходимо указать путь к нему, например /var/hg/projectname. Репозитории в /var/hg необходимо создать вручную для каждого проекта и инициализировать командой ( hg init ).
После создания нового репозитория надо убедиться, что у него установлены нужные права доступа:
В принципе, есть возможность автоматизировать создание репозиториев. Информация об этом есть в руководстве по ссылке HowTo Install Redmine 1.2.x with Mercurial and Subversion on Ubuntu Server 10.04
Уведомления о фиксации изменений по email
Redmine поддерживает уведомления о разных событиях (изменениях в жизни баг/фич и т.п.). Для того чтобы пользоваться этим функционалом достаточно настроить способ отправки email-сообщений. Делается это в файле /usr/share/redmine/config/configuration.yml В файле имеются шаблоны для разных конфигураций. Нужно разкомментировать и отредактировать нужный.
Обратите внимание, что каждая секция в файле configuration.yml сдвинута на два пробела. Это важно.
Базовые уведомления должны быть доступны после указания способа рассылки электронных писем. Однако для уведомлений об изменениях в репозитории необходимо использовать внешний плагин. Скачать его можно с сайта github.com/lpirl/redmine_diff_email.
Установим этот плагин. Для этого скопируем содержимое плагина в каталог /usr/share/redmine/plugins/redmine_diff_email. В соответствии с инструкцией по установке плагина изменяем файл /usr/share/redmine/app/views/repositories/_form.html.erb:
Оригинальный плагин работает с устаревшей версией redmine. Для redmine-3.3 нужно внести изменения в файл
/usr/share/redmine/plugins/redmine_diff_email/db/migrate/002_add_repositories_is_diff_email_attached.rb. Содержимое файла должно быть таким:
После этого в каталоге /usr/share/redmine выполнить команду для обновления базы данных:
Если плагин установлен правильно, то в списке плагинов Administration → Plugins появится Redmine Diff Email Plugin, а также в веб-интерфейсе Redmine SomeProject → «Settings» Tab → «Repositories» Tab → «Edit» появятся настройки уведомлений.
Кроме того, чтобы информация об изменениях в репозиториях автоматически отслеживалась Redmine, необходимо выполнить дополнительные действия. Сначала нужно включить WS для управления репозиториями и сгенерировать API key. Как это делается:
* В web-интерфейсе Redmine в меню Administration выбрать Settings
* Перейти на вкладку Repositories
* Включить ‘Enable WS for repository management’
* Кликнуть на ссылку ‘Generate a key’
* Сохранить изменения кнопкой ‘Save’
Далее создаём скрипт:
Добавляем следующий текст и сохраняем: (необходимо заменить [your API key] сгенерированным в API-ключом)
Устанавливаем права доступа для созданного файла:
Остаётся добавить в /var/hg/hgweb.config секцию [hooks], чтобы скрипт fetch_changes выполнялся после каждого коммита:
Теперь при изменениях в репозитории Redmine будет автоматически отсылать уведомления участникам проекта.
Redmine. Как писать плагины
В своем прошлом посте я постарался достаточно детально описать все тонкости установки Redmine на Linux Ubuntu. В этом, хочу рассказать о тонкостях написания плагинов под Redmine, об основных возможностях изменения функциональности стандартного Redmine, о подводных камнях, которые встречались моей команде на этом пути.
Думаю, эта статья будет полезна тем, кто уже знаком с основами фреймворка Ruby on Rails и хочет начать разрабатывать плагины для Redmine.
Прежде всего, стоит разделить все плагины Redmine на две категории:
В первую попадают те плагины, которые фактически не затрагивают функциональность стандартного Redmine. По сути это обычные Rails-приложения внутри Redmine, с ними возникает мало сложностей, поэтому они малоинтересны. На официальном сайте Redmine есть неплохой туториал, подробно описывающий как создать плагин для голосования.
Все немного сложнее, когда плагин должен изменять встроенную функциональность!
Начнем с команды, которая создает структуру папок для плагина Redmine. Пусть наш плагин будет называться Luxury Buttons. Перейдем в корневую папку Redmine, запустим команду, создающую структуру папок:
После выполнения команды в папке plugins должна появиться папка luxury_buttons со следующей структурой:
В папку lib стоит сразу добавить, папку, совпадающую с названием плагина, т.е. папку luxury_buttons (далее папка патчинга). В этой папке, в дальнейшем, будут лежать файлы патчинга различных методов Redmine.
Почему мы назвали эту папку также как назвали плагин? Это просто рекомендация, папку можно назвать и по-другому, но тут возникает первый подводный камень: если в другом плагине название этой папки будет совпадать, и будет совпадать название файла патчинга, то один из файлов патчинга просто не примениться! Поэтому, я рекомендую, называть папку патчинга одноименно с названием плагина. Такой способ минимизирует возникновение ошибок!
Когда плагин должен что-то добавить во вьюшке.
Допустим нам нужно что-то добавить в стандартную вьюшку Redmine. Самый простой и самый неправильный способ сделать это – переписать вьюшку внутри плагина. Обычно это делается путем копирования файла-вьюшки из ядра Redmine в соответствующую директорию плагина и дальнейшим редактированием этого файла. Вот, например, в одном из наших плагинов, мы переписываем вьюшку с формой сохранения запроса.
Почему так делать плохо:
Хук во вьюшке – это такая строчка кода, которая позволяет встроить во вьюшку свое содержимое. Чтобы найти хук, нужно просто выполнить поиск подстроки «hook» по всем файлам Redmine или можно воспользоваться вот этой табличкой.
Подключение хука
Мы стараемся хранить все подключения хуков вьюшек в одном файле. Этот файл нужно подключить в init.rb вот так:
Содержимое самого файла может быть таким:
Название первого модуля должно совпадать с названием плагина, второго – с названием папки патчинга.
Внутри класса находятся функции, которые показывают, в какой хук какой шаблон нужно отрендерить.
Если два плагина будут использовать один и тот же хук, то во вьюшки появиться содержимое и из первого и из второго плагина. Т.е. хуки не переписывают друг друга.
Для этого, проще всего, использовать хук «view_layouts_base_html_head», он позволяет вставить содержимое в шапку страницы. Нам необходимо вставить ссылку на подключение js-файла с логикой вырезания или добавления определенных DOM-элементов. Что бы данный js-файл не подгружался на страницах, на которых он не нужен, его загрузку лучше загнать в условное выражение. Т.е. отсекать загрузку файла по экшину и контроллеру. Например:
В папке assets/javascript плагина должен находиться файл «luxury_buttons_common.js»:
Иногда, более грамотно, встраивать строку подключения js-файла не через хук «view_layouts_base_html_head», а через определенный хук, который встраивает содержимое на ограниченном, нужном нам количестве страниц. Например, если нам нужно, что-то добавить или вырезать на странице задачи, то можно воспользоваться хуком «view_issues_form_details_bottom».
В таком случае, что бы файл подключался не в тело документа, а в шапку, нужно использовать конструкцию:
Правда, с методом «content_for» в плагинах, от версии к версии возникают сложности.
Как изменять методы моделей, контроллеров и хелперов.
Изменение (патчинг) методов во многом похоже на изменение вьюшек и несет схожие проблемы.
Хуки в контроллерах и моделях
В контроллерах и моделях тоже встречаются хуки. Подключаются они иначе. В init.rb должна быть строчка которая подключает определенный хук. Например, хук, который вызывается перед сохранением новой задачи:
В директории патчинга должен быть файл «controller_issues_new_before_save_hook.rb», например, с таким содержимым:
Название модуля должно совпадать с названием плагина, название класса – с названием файла.
В данном случае, мы реализуем возможность автоматического назначения новой задачи на автора.
Патчинг методов
Как и во вьюшках, нужные хуки в Redmine есть далеко не всегда. И тогда нужно патчить методы модели, хелпера или контроллера.
Сперва, нужно подключить файл патчинга в init.rb. К примеру, нам нужно пропатчить метод «read_only_attribute_names» модели «Issue».
В папке патчинга должен быть файл «issue_patch.rb», примерно следующего содержания:
мы порождаем два метода «read_only_attribute_names_with_luxury_buttons» и «read_only_attribute_names_without_luxury_buttons».
Первый метод теперь будет вызываться вместо стандартного метода модели «read_only_attribute_names», второй метод является алиасом для стандартного метода «read_only_attribute_names».
Сочетанием двух методов можно патчить стандартный метод Redmine. В нашем примере, мы сперва вызываем стандартный метод Redmine, который возвращает массив значений, а затем, добавляем значения в этот массив.
Если в стандартном методе Redmine в новой версии что-то поменяется, то шансов, что наш патчинг будет работать корректно гораздо больше, чем если бы мы просто переписали стандартный метод Redmine добавив в него свою логику.
Важно! В Redmine наблюдаются какие-то проблемы с патчингом модели User. Для корректного патчинга нужно явно подключить следующие файлы:
Статья не содержит всего, что хотелось бы сказать о написании плагинов под Redmine. Я попытался собрать основные методологии и подводные камни. Надеюсь статья будет полезна.