From f5b547e8ce7aaedb8f61ff0efc13629d1515b6d3 Mon Sep 17 00:00:00 2001 From: Pavel Gnedov Date: Mon, 5 Feb 2024 08:17:45 +0700 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B8=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BF=D0=BE=20=D1=83=D1=81=D1=82=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configs.examples/calendar-enhancer.jsonc | 22 ++ .../configs.examples/current-user-rules.jsonc | 14 ++ configs/configs.examples/eccm-config.jsonc | 24 ++ .../issue-event-emitter-config.jsonc | 50 ++++ configs/configs.examples/main-config.jsonc | 18 ++ .../redmine-status-changes-config.jsonc | 225 ++++++++++++++++++ .../redmine-statuses-config.jsonc | 60 +++++ .../simple-kanban-board-config.jsonc | 4 + docs/Установка.md | 107 +++++++++ 9 files changed, 524 insertions(+) create mode 100644 configs/configs.examples/calendar-enhancer.jsonc create mode 100644 configs/configs.examples/current-user-rules.jsonc create mode 100644 configs/configs.examples/eccm-config.jsonc create mode 100644 configs/configs.examples/issue-event-emitter-config.jsonc create mode 100644 configs/configs.examples/main-config.jsonc create mode 100644 configs/configs.examples/redmine-status-changes-config.jsonc create mode 100644 configs/configs.examples/redmine-statuses-config.jsonc create mode 100644 configs/configs.examples/simple-kanban-board-config.jsonc create mode 100644 docs/Установка.md diff --git a/configs/configs.examples/calendar-enhancer.jsonc b/configs/configs.examples/calendar-enhancer.jsonc new file mode 100644 index 0000000..b2a0df9 --- /dev/null +++ b/configs/configs.examples/calendar-enhancer.jsonc @@ -0,0 +1,22 @@ +{ + // TODO: + "useForProjects": [ + "Test project name 1", + "Test project name 2" + ], + + // TODO: + "customFields": [ + { + "dateFormat": "yyyy-MM-dd HH:mm", + "customFieldName": "Название кастомного поля 1", + "alias": "Название кастомного поля 1" + } + ], + + "descriptionCalendarParams": { + "title": "Календарь:", + "lineRegexp": "(?<=\\*\\ ).+" + }, + "calendarEventsKey": "calendar" +} \ No newline at end of file diff --git a/configs/configs.examples/current-user-rules.jsonc b/configs/configs.examples/current-user-rules.jsonc new file mode 100644 index 0000000..ac97b7c --- /dev/null +++ b/configs/configs.examples/current-user-rules.jsonc @@ -0,0 +1,14 @@ +{ + "New": "dev", + "In Progress": "dev", + "Re-opened": "dev", + "Code Review": "cr", + "Resolved": "qa", + "Testing": "qa", + "Wait Release": "dev", + "Pending": "dev", + "Feedback": "qa", + "Closed": "dev", + "Rejected": "dev", + "*": "dev" +} \ No newline at end of file diff --git a/configs/configs.examples/eccm-config.jsonc b/configs/configs.examples/eccm-config.jsonc new file mode 100644 index 0000000..8757829 --- /dev/null +++ b/configs/configs.examples/eccm-config.jsonc @@ -0,0 +1,24 @@ +// TODO: +{ + "currentVersions": ["1", "0.1"], + "projectName": "Test project name 1", + "currentIssuesStatuses": ["In Progress", "Re-opened", "Code Review", "Resolved", "Testing", "Feedback"], + "groups": [ + { + "name": "Dev backend", + "people": [ + "User Developer" + ] + }, + { + "name": "QA", + "people": [ + "Redmine Admin" + ] + } + ], + "dailyTime": { + "hour": 10, + "minute": 30 + } +} \ No newline at end of file diff --git a/configs/configs.examples/issue-event-emitter-config.jsonc b/configs/configs.examples/issue-event-emitter-config.jsonc new file mode 100644 index 0000000..2b72666 --- /dev/null +++ b/configs/configs.examples/issue-event-emitter-config.jsonc @@ -0,0 +1,50 @@ +{ + + // "mailListener": { + // "issueNumberParser": "\\b(?<=#)\\d+\\b", + // "imapSimpleConfig": { + // "imap": { + // "user": "", + // "password": "", + // "host": "", + // "port": 143, + // // tls: true, + // "autotls": "always", + // "authTimeout": 5000 + // } + // }, + // "updateInterval": 180000, // 3 min + // "boxName": "INBOX" + // }, + + "rssListener": { + "subscriptions": [ + { + "url": "https://REDMINE_HOST/projects/proj/activity.atom?key=....", // TODO + "issueNumberParser": "\\b(?<=#)\\d+\\b" + }, + { + "url": "https://REDMINE_HOST/activity.atom?key=....", // TODO + "issueNumberParser": "\\b(?<=#)\\d+\\b" + } + ], + "updateInterval": 10000 // 10 sec + }, + + "issueChangesQueue": { + "updateInterval": 5000, // 5 sec + "itemsLimit": 3 + }, + "redmineUrlPrefix": "https://REDMINE_API_TOKEN@REDMINE_HOST", // TODO + "redmineUrlPublic": "https://REDMINE_HOST", // TODO + "webhooks": [], + + "couchDb": { + "url": "http://admin:password@localhost:5984", // <- TODO: Указать host, port, username и password для доступа к couchdb + "dbs": { + "users": "redmine_users", + "issues": "redmine_issues", + "dashboards": "dashboards" + } + } +} \ No newline at end of file diff --git a/configs/configs.examples/main-config.jsonc b/configs/configs.examples/main-config.jsonc new file mode 100644 index 0000000..d7d9d69 --- /dev/null +++ b/configs/configs.examples/main-config.jsonc @@ -0,0 +1,18 @@ +{ + "couchDb": { + "dbs": { + "changes": "redmine_changes", + "userMetaInfo": "user_meta_info", + "eccmDailyReports": "eccm_daily_reports", + "eccmDailyReportsUserComments": "eccm_daily_reports_user_comments" + } + }, + "telegramBotToken": "....", // <- TODO: Указать token от бота telegram + "personalMessageTemplate": "{{{issue_url}}} {{{sender_name}}}:\n\n{{{message}}}", + "periodValidityNotification": 43200000, // 12h + "tagManager": { + "updateInterval": 15000, + "updateItemsLimit": 3, + "tagsCustomFieldName": "Tags" + } +} \ No newline at end of file diff --git a/configs/configs.examples/redmine-status-changes-config.jsonc b/configs/configs.examples/redmine-status-changes-config.jsonc new file mode 100644 index 0000000..0c428cc --- /dev/null +++ b/configs/configs.examples/redmine-status-changes-config.jsonc @@ -0,0 +1,225 @@ +// TODO: Указать правила для формирования сообщений с уведомлениями об изменениях статусов +[ + { + "default": false, + "from": "New", + "to": "In Progress", + "messages": [ + { + "recipient": "dev", + "changes_message": "{{dev.name}} взял в работу задачу #{{issue_id}}" + } + ] + }, + { + "default": false, + "from": "In Progress", + "to": "Code Review", + "messages": [ + { + "recipient": "dev", + "changes_message": "{{dev.name}} завершил разработку по задаче #{{issue_id}} и передал на ревью {{cr.name}}" + }, + { + "recipient": "cr", + "changes_message": "{{cr.name}} получил задачу #{{issue_id}} на ревью от {{dev.name}}", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{issue_subject}}:\n{{dev.name}} завершил разработку по задаче и передал вам на ревью\n\n{{journal_note}}" + } + ] + }, + { + "default": false, + "from": "Code Review", + "to": "Re-opened", + "messages": [ + { + "recipient": "cr", + "changes_message": "{{cr.name}} вернул задачу #{{issue_id}} на доработку {{dev.name}}" + }, + { + "recipient": "dev", + "changes_message": "{{dev.name}} получил задачу #{{issue_id}} на доработку после завершения ревью {{cr.name}}", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{cr.name}} вернул вам с ревью на доработку задачу\n\n{{journal_note}}" + } + ] + }, + { + "default": false, + "from": "Re-opened", + "to": "In Progress", + "messages": [ + { + "recipient": "dev", + "changes_message": "{{dev.name}} продолжил работу над задачей #{{issue_id}}" + } + ] + }, + { + "default": false, + "from": "Code Review", + "to": "Resolved", + "messages": [ + { + "recipient": "cr", + "changes_message": "{{cr.name}} завершил ревью задачи {{issue_id}} и передал её на тест {{qa.name}}" + }, + { + "recipient": "qa", + "changes_message": "{{qa.name}} получил на тест задачу #{{issue_id}} после разработки {{dev.name}} и ревью {{cr.name}}", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{dev.name}} завершил разработку по задаче, а {{cr.name}} выполнил ревью и передали теперь вам для проверки\n\n{{journal_note}}" + }, + { + "recipient": "dev", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{cr.name}} выполнил ревью вашей задачи и передал далее на проверку {{qa.name}}\n\n{{journal_note}}" + } + ] + }, + { + "default": false, + "from": "Re-opened", + "to": "Code Review", + "messages": [ + { + "recipient": "dev", + "changes_message": "{{dev.name}} выполнил доработки и перевёл задачу #{{issue_id}} на ревью {{cr.name}}" + }, + { + "recipient": "cr", + "changes_message": "{{cr.name}} получил задачу #{{issue_id}} на повторное ревью от {{dev.name}}", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{dev.name}} выполнил по задаче доработки и теперь вы можете сделать ревью\n\n{{journal_note}}" + } + ] + }, + { + "default": false, + "from": "Resolved", + "to": "Closed", + "messages": [ + { + "recipient": "qa", + "changes_message": "{{qa.name}} протестировал задачу #{{issue_id}} и закрыл" + }, + { + "recipient": "dev", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{qa.name}} проверил и закрыл вашу задачу" + } + ] + }, + { + "default": false, + "from": "Testing", + "to": "Re-opened", + "messages": [ + { + "recipient": "qa", + "changes_message": "{{qa.name}} вернул задачу #{{issue_id}} на доработку {{dev.name}}" + }, + { + "recipient": "dev", + "changes_message": "{{dev.name}} получил от {{qa.name}} задачу #{{issue_id}} на доработку", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{qa.name}} вернул вам с тестирования задачу на доработку\n\n{{journal_note}}" + } + ] + }, + { + "default": false, + "from": "Resolved", + "to": "Re-opened", + "messages": [ + { + "recipient": "qa", + "changes_message": "{{qa.name}} вернул задачу #{{issue_id}} на доработку {{dev.name}}" + }, + { + "recipient": "dev", + "changes_message": "{{dev.name}} получил от {{qa.name}} задачу #{{issue_id}} на доработку", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{qa.name}} вернул вам с тестирования задачу на доработку\n\n{{journal_note}}" + } + ] + }, + { + "default": false, + "from": "Resolved", + "to": "Testing", + "messages": [ + { + "recipient": "qa", + "changes_message": "{{qa.name}} начал проверять задачу #{{issue_id}}" + } + ] + }, + { + "default": false, + "from": "Testing", + "to": "Closed", + "messages": [ + { + "recipient": "qa", + "changes_message": "{{qa.name}} протестировал задачу #{{issue_id}} и закрыл" + }, + { + "recipient": "dev", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{qa.name}} проверил и закрыл вашу задачу" + } + ] + }, + { + "default": false, + "to": "Rejected", + "messages": [ + { + "recipient": "initiator", + "changes_message": "{{initiator.name}} изменил статус задачи {{issue_id}} с {{old_status.name}} на {{new_status.name}} (dev - {{dev.name}}, cr - {{cr.name}}, qa - {{qa.name}})" + } + ] + }, + { + "default": true, + "messages": [ + { + "recipient": "initiator", + "changes_message": "{{initiator.name}} изменил статус задачи #{{issue_id}} с {{old_status.name}} на {{new_status.name}} (dev - {{dev.name}}, cr - {{cr.name}}, qa - {{qa.name}})" + }, + { + "recipient": "dev", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{initiator.name}} изменил статус задачи с {{old_status.name}} на {{new_status.name}}" + }, + { + "recipient": "current_user", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{initiator.name}} изменил статус задачи с {{old_status.name}} на {{new_status.name}}" + } + ] + }, + { + "default": false, + "new_issue": true, + "from": "New", + "to": "New", + "messages": [ + { + "recipient": "author", + "changes_message": "{{author.name}} создал новую задачу #{{issue_id}} {{#if current_user}}для {{current_user.name}}{{/if}}" + }, + { + "recipient": "current_user", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{author.name}} создал новую задачу и назначил её на вас" + } + ] + }, + { + "default": false, + "from": "Re-opened", + "to": "Resolved", + "messages": [ + { + "recipient": "dev", + "changes_message": "{{dev.name}} перевёл задачу #{{issue_id}} на повторную проверку {{qa.name}}" + }, + { + "recipient": "qa", + "changes_message": "{{qa.name}} получил задачу #{{issue_id}} на повторную проверку от {{dev.name}}", + "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{dev.name}} выполнил по задаче доработки и теперь вы можете проверить повторно\n\n{{journal_note}}" + } + ] + } +] \ No newline at end of file diff --git a/configs/configs.examples/redmine-statuses-config.jsonc b/configs/configs.examples/redmine-statuses-config.jsonc new file mode 100644 index 0000000..af3f9d2 --- /dev/null +++ b/configs/configs.examples/redmine-statuses-config.jsonc @@ -0,0 +1,60 @@ +// TODO: Указать какие статусы могут быть в вашем Redmine +[ + { + "id": 1, + "name": "New" + }, + { + "id": 4, + "name": "In Progress" + }, + { + "id": 5, + "name": "Re-opened" + }, + { + "id": 6, + "name": "Code Review" + }, + { + "id": 7, + "name": "Resolved" + }, + { + "id": 8, + "name": "Testing" + }, + { + "id": 9, + "name": "Wait Release" + }, + { + "id": 10, + "name": "Pending" + }, + { + "id": 11, + "name": "Feedback" + } + + // { + // "id": 5, + // "name": "Closed", + // "is_closed": true + // }, + // { + // "id": 6, + // "name": "Rejected", + // "is_closed": true + // }, + // { + // "id": 7, + // "name": "Confirming" + // }, + // { + // "id": 12, + // "name": "Frozen", + // "is_closed": true + // }, + // ... +] \ No newline at end of file diff --git a/configs/configs.examples/simple-kanban-board-config.jsonc b/configs/configs.examples/simple-kanban-board-config.jsonc new file mode 100644 index 0000000..09676d9 --- /dev/null +++ b/configs/configs.examples/simple-kanban-board-config.jsonc @@ -0,0 +1,4 @@ +// deprecated +{ + "path": "/path/to/eltex-redmine-issue-event-emitter/configs/kanban-boards" +} \ No newline at end of file diff --git a/docs/Установка.md b/docs/Установка.md new file mode 100644 index 0000000..1419f3b --- /dev/null +++ b/docs/Установка.md @@ -0,0 +1,107 @@ +# Установка + +Инструкция для установки приложения + +## Требования к системе + +Требования к окружению для сборки и запуска приложения: + +- CouchDB в качестве хранилища данных +- NodeJS для сборки и запуска backend-а и frontend-а + +Доступы к внешним системам: + +- Токен для подключения telegram-бота +- Токен для доступа к API Redmine + +## Подготовка и запуск couchdb + +CouchDB необходим для хранения данных. + +Для запуска можно воспользоваться любым удобным сопособом. + +Пример с помощью docker-compose + +1. `docker-compose.yml`: + + ```yaml + version: '3.1' + + services: + couchdb: + image: apache/couchdb:latest + restart: always + ports: + - 127.0.0.1:5984:5984 + volumes: + - ./couchdb-data:/opt/couchdb/data + environment: + - COUCHDB_USER + - COUCHDB_PASSWORD + ``` + +2. Так же нужно указать имя и пароль с помощью файла `.env`: + + ``` + COUCHDB_USER=admin + COUCHDB_PASSWORD=password + ``` + +3. Создать папку `couchdb-data` для вольюма определённого для контейнера в `docker-compose.yml`: + + ```shell + mkdir couchdb-data + ``` + +4. Для запуска воспользоваться командой: + + ```shell + docker-compose up -d + ``` + +## Установка зависимостей для backend-а и frontend-а + +Backend и frontend написаны на языке typescript. Для загрузки и запуска необходимо выполнить: + +```shell +cd $PROJECT_DIR && npm install +cd $PROJECT_DIR/frontend && npm install +``` + +## Настройка + +Нужно скопировать все конфигурационные файлы `CONFIG_NAME.jsonc.dist` в `CONFIG_NAME.jsonc`: + +```shell +cd $PROJECT_DIR/configs/ + +cp calendar-enhancer.jsonc.dist calendar-enhancer.jsonc +cp current-user-rules.jsonc.dist current-user-rules.jsonc +cp eccm-config.jsonc.dist eccm-config.jsonc +cp issue-event-emitter-config.jsonc.dist issue-event-emitter-config.jsonc +cp main-config.jsonc.dist main-config.jsonc +cp redmine-status-changes-config.jsonc.dist redmine-status-changes-config.jsonc +cp redmine-statuses-config.jsonc.dist redmine-statuses-config.jsonc +cp simple-kanban-board-config.jsonc.dist simple-kanban-board-config.jsonc +``` + +Или можно взять за основу файлы из папки `$PROJECT_DIR/configs/configs.example/` или в качестве примеров для заполнения. В этих файлах можно обратить внимание на строчки с TODO и рекоментациями что нужно указать в конфигурационном файле. Там могут встречаться такие рекомендации как: + +* Указать host, port, username и password для доступа к couchdb +* Указать token от бота telegram + +## Запуск приложения + +1. Нужно сделать сборку frontend-а: + + ```shell + cd $PROJECT_DIR/frontend/ && npm run build + ``` + +2. Сделать сборку или можно просто запустить backend: + + ```shell + cd $PROJECT_DIR/ && npm run start + ``` + +Если нужно запустить приложение с явным указанием порта, то можно воспользоваться переменной окружения `PORT`. \ No newline at end of file