From 0f7a15482af576c9cd6ff151737b6b7858594f5b Mon Sep 17 00:00:00 2001 From: Maximov Valery Date: Wed, 15 May 2019 10:51:46 +0300 Subject: [PATCH] =?UTF-8?q?1.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=84=D0=BE=D1=80=D0=BC=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BE=D1=82=D1=87=D0=B5=D1=82?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=20=D1=80=D0=B0=D0=B7=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D1=87=D0=B8=D0=BA=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2. Выполнены рефакторинг и исправление ошибок --- README.md | 10 +- examples/example-usr-report.cfg-file.json | 8 + examples/example-usr-report.json | 29 ++ src/Классы/КомандаЗакрытьИшузы.os | 140 +++------- src/Классы/КомандаСгенерироватьОтчет.os | 129 +++------ ...омандаСгенерироватьОтчетПоПользователям.os | 252 ++++++++++++++++++ src/Модули/ОбщегоНазначения.os | 148 ++++++++++ src/Модули/ПараметрыСистемы.os | 12 +- src/Модули/Сонар.os | 123 ++++++++- 9 files changed, 636 insertions(+), 215 deletions(-) create mode 100644 examples/example-usr-report.cfg-file.json create mode 100644 examples/example-usr-report.json create mode 100644 src/Классы/КомандаСгенерироватьОтчетПоПользователям.os create mode 100644 src/Модули/ОбщегоНазначения.os diff --git a/README.md b/README.md index c160910..92b97c0 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,14 @@ SonarQube может создавать несколько замечаний п На данный момент поддерживаются следующие варианты формирования отчета: -- **JSON** - формируется отчет в формате json, метрики выгружаются дважды - для идентификатора метрики и для русского представления. [Пример: examples\example-report.json](examples\example-report.json) -- **HTML** - формируется отчет в формате html, метрики выгнржаются только для русского представления. [Пример: examples\example-report.html](examples\example-report.html) +- **JSON** - формируется отчет в формате json, метрики выгружаются дважды - для идентификатора метрики и для русского представления. [Пример: examples\example-report.json](examples/example-report.json) +- **HTML** - формируется отчет в формате html, метрики выгнржаются только для русского представления. [Пример: examples\example-report.html](examples/example-report.html) + +### Сводный отчет по разработчикам + +При необходимоси получить отчет по разработчикам (не конкретные замечания, а "температуру") и понять, кто в команде как работает можно вручную собирать информацию по страницам SonarQube, но проще использовать **`sonar-helper`**, вызвав команду **`usr-report`** и проанализировать полученный результат. + +На данный момент поддерживается вариант формирования отчета в формате **JSON**. [Пример отчета: examples\example-usr-report.json](examples/example-usr-report.json) ## Примеры diff --git a/examples/example-usr-report.cfg-file.json b/examples/example-usr-report.cfg-file.json new file mode 100644 index 0000000..aa84763 --- /dev/null +++ b/examples/example-usr-report.cfg-file.json @@ -0,0 +1,8 @@ +{ + "--token": "2ef785ca946170b7086668132175eb01386943a1", + "--server": "http://my.sonar.server:9000", + "--projects": "bsp,mdm", + "--statuses": "OPEN", + "--report-path": "usr-rep.json", + "--report-format": "JSON" +} diff --git a/examples/example-usr-report.json b/examples/example-usr-report.json new file mode 100644 index 0000000..4104545 --- /dev/null +++ b/examples/example-usr-report.json @@ -0,0 +1,29 @@ +{ +"ДатаФормирования": "2019-05-06T14:17:17.5125591", +"СерверSonarQube": "http:\/\/my.sonar.server:9000", +"Количество": 2, +"Замечания": [ +{ +"КлючПроекта": "mdm", +"Статус": "OPEN", +"Автор": "my.user@mail.domain", +"Отвественный": "my.user", +"Правило": "RuleCode", +"Критичность": "MAJOR", +"Тип": "BUG", +"Время": 40, +"Количество": 20 +}, +{ +"КлючПроекта": "bsp", +"Статус": "OPEN", +"Автор": "my.user@mail.domain", +"Отвественный": "my.user", +"Правило": "RuleCode2", +"Критичность": "MINOR", +"Тип": "CODE_SMELL", +"Время": 29, +"Количество": 29 +} +] +} diff --git a/src/Классы/КомандаЗакрытьИшузы.os b/src/Классы/КомандаЗакрытьИшузы.os index b78d09c..30f5160 100644 --- a/src/Классы/КомандаЗакрытьИшузы.os +++ b/src/Классы/КомандаЗакрытьИшузы.os @@ -1,15 +1,20 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Служебный модуль с реализацией работы команды issue-resolver +// +// (C) Maximov Valery (aka theshadowco) +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + Перем Лог; -Перем Токен; -Перем АдресСервера; -Перем РодительскийПроект; Перем ДочерниеПроекты; Перем ИсключаемыеПроекты; Перем Статусы; -Перем ИзEDTВКонфигуратор; -Перем Теги; Перем МаксимальноеКоличествоСтатусов; +Перем ПрочитанныеПараметры; + /////////////////////////////////////////////////////////////////////////////////////////////////// // Прикладной интерфейс /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -54,15 +59,19 @@ Лог = ДополнительныеПараметры.Лог; ОшибокНет = ПрочитатьПараметрыЗапуска(ПараметрыКоманды); Если НЕ ОшибокНет Тогда - Возврат СообщитьОбОшибке("Ошибка запуска"); + Возврат ОбщегоНазначения.СообщитьОбОшибке("Ошибка запуска"); КонецЕсли; - + + АдресСервера = ПрочитанныеПараметры.Получить("АдресСервера"); + Токен = ПрочитанныеПараметры.Получить("Токен"); + РодительскийПроект = ПрочитанныеПараметры.Получить("РодительскийПроект"); + Лог.Информация("Получение информации о проектах"); ПроектыSQ = Сонар.ПолучитьПроекты(АдресСервера, Токен); Лог.Информация("Получение информации о родительском проекте"); ОписаниеРодительскогоПроекта = ПроектыSQ.Получить(РодительскийПроект); Если ОписаниеРодительскогоПроекта = Неопределено Тогда - Возврат СообщитьОбОшибке(СтрШаблон("Родительский проект `%1` в списке проектов не обнаружен", РодительскийПроект)); + Возврат ОбщегоНазначения.СообщитьОбОшибке(СтрШаблон("Родительский проект `%1` в списке проектов не обнаружен", РодительскийПроект)); КонецЕсли; Лог.Информация("Получение закрываемых замечаний из родительского проекта"); @@ -70,7 +79,7 @@ АдресСервера, Токен, ОписаниеРодительскогоПроекта, СтрСоединить(Статусы, ","), - ИзEDTВКонфигуратор); + ПрочитанныеПараметры.Получить("ИзEDTВКонфигуратор")); Если НЕ ЗамечанияРодительскогоПроекта.Количество() Тогда @@ -102,6 +111,7 @@ КонецЦикла; Лог.Информация("Закрытие замечаний в дочерних проектах"); + Теги = ПрочитанныеПараметры.Получить("Теги"); Для Каждого ДочернийПроект Из ДочерниеПроекты Цикл Лог.Информация("Закрытие замечаний в проекте `%1`", ДочернийПроект); ОписаниеПроекта = ПроектыSQ.Получить(СокрЛП(ДочернийПроект)); @@ -127,103 +137,33 @@ Функция ПрочитатьПараметрыЗапуска(ПараметрыКоманды) + ПрочитанныеПараметры = ОбщегоНазначения.ПрочитатьПараметрыЗапуска(ПараметрыКоманды, Истина); + ОшибокНет = ПрочитанныеПараметры.Получить("ОшибокНет"); МаксимальноеКоличествоСтатусов = 5; - ОшибокНет = Истина; - Токен = ПараметрыКоманды["--token"]; - АдресСервера = ПараметрыКоманды["--server"]; - РодительскийПроект = ПараметрыКоманды["--parent-project"]; - ДочерниеПроектыСтрокой = ПараметрыКоманды["--child-projects"]; - ИсключаемыеПроектыСтрокой = ПараметрыКоманды["--exclude-projects"]; - СтатусыСтрокой = ПараметрыКоманды["--statuses"]; - Теги = ПараметрыКоманды["--tags"]; - ИзEDTВКонфигуратор = ПараметрыКоманды["--edt2cfg"]; - - ПутьККонфигурационномуФайлу = ПараметрыКоманды["--cfg-file"]; - Если ПутьККонфигурационномуФайлу <> Неопределено Тогда - - Файл = Новый Файл(ПутьККонфигурационномуФайлу); - Если Файл.Существует() Тогда - ТекстовыйДокумент = Новый ТекстовыйДокумент(); - ТекстовыйДокумент.Прочитать(ПутьККонфигурационномуФайлу); - Лог.Отладка("Содержимое конфигурационного файла: %1%2", Символы.ПС, ТекстовыйДокумент.ПолучитьТекст()); - JSON = Новый ЧтениеJSON(); - JSON.УстановитьСтроку(ТекстовыйДокумент.ПолучитьТекст()); - ПараметрыИзФайла = ПрочитатьJSON(JSON, Истина); - Если Токен = Неопределено Тогда - Токен = ПараметрыИзФайла.Получить("--token"); - КонецЕсли; - Если АдресСервера = Неопределено Тогда - АдресСервера = ПараметрыИзФайла.Получить("--server"); - КонецЕсли; - Если РодительскийПроект = Неопределено Тогда - РодительскийПроект = ПараметрыИзФайла.Получить("--parent-project"); - КонецЕсли; - Если ДочерниеПроектыСтрокой = Неопределено Тогда - ДочерниеПроектыСтрокой = ПараметрыИзФайла.Получить("--child-projects"); - КонецЕсли; - Если ИсключаемыеПроектыСтрокой = Неопределено Тогда - ИсключаемыеПроектыСтрокой = ПараметрыИзФайла.Получить("--exclude-projects"); - КонецЕсли; - Если СтатусыСтрокой = Неопределено Тогда - СтатусыСтрокой = ПараметрыИзФайла.Получить("--statuses"); - КонецЕсли; - Если Теги = Неопределено Тогда - Теги = ПараметрыИзФайла.Получить("--tags"); - КонецЕсли; - Если ИзEDTВКонфигуратор = Ложь И ПараметрыИзФайла.Получить("--edt2cfg") <> Неопределено Тогда - ИзEDTВКонфигуратор = ПараметрыИзФайла.Получить("--edt2cfg"); - КонецЕсли; - Иначе - Лог.Ошибка("Конфигурационный файл по пути `%1` не обнаружен", ОбернутьЗначениеДляПечати(ПутьККонфигурационномуФайлу)); - ОшибокНет = Ложь; - КонецЕсли; - - КонецЕсли; - - Лог.Отладка("Прочитанные параметры:"); - Лог.Отладка(" Токен = `%1`", ОбернутьЗначениеДляПечати(Токен)); - Лог.Отладка(" Адрес сервера = `%1`", ОбернутьЗначениеДляПечати(АдресСервера)); - Лог.Отладка(" Ключ родительского проекта = `%1`", ОбернутьЗначениеДляПечати(РодительскийПроект)); - Лог.Отладка(" Ключ дочерних проектов (строкой) = `%1`", ОбернутьЗначениеДляПечати(ДочерниеПроектыСтрокой)); - Лог.Отладка(" Ключ исключаемых проектов (строкой) = `%1`", ОбернутьЗначениеДляПечати(ИсключаемыеПроектыСтрокой)); - Лог.Отладка(" Статусы строкой = `%1`", ОбернутьЗначениеДляПечати(СтатусыСтрокой)); - Лог.Отладка(" Устанавливаемые теги = `%1`", ОбернутьЗначениеДляПечати(Теги)); - Лог.Отладка(" Нужно переводить из EDT = `%1`", ОбернутьЗначениеДляПечати(ИзEDTВКонфигуратор)); - - Если Не ЗначениеЗаполнено(Токен) Тогда - Лог.Ошибка("Не указан токен для авторизации"); - ОшибокНет = Ложь; - КонецЕсли; - - Если Не ЗначениеЗаполнено(АдресСервера) Тогда - Лог.Ошибка("Не указан адрес сервера SonarQube"); - ОшибокНет = Ложь; - КонецЕсли; - - Если Не ЗначениеЗаполнено(РодительскийПроект) Тогда + Если Не ЗначениеЗаполнено(ПрочитанныеПараметры.Получить("РодительскийПроект")) Тогда Лог.Ошибка("Не указан ключ родительского проекта"); ОшибокНет = Ложь; КонецЕсли; - Если Не ЗначениеЗаполнено(ДочерниеПроектыСтрокой) Тогда - Лог.Ошибка("Не указаны ключ дочерних проектов"); + Если Не ЗначениеЗаполнено(ПрочитанныеПараметры.Получить("ДочерниеПроектыСтрокой")) Тогда + Лог.Ошибка("Не указаны ключи дочерних проектов"); ОшибокНет = Ложь; Иначе - ДочерниеПроекты = СтрРазделить(ДочерниеПроектыСтрокой, ",", Ложь); + ДочерниеПроекты = СтрРазделить(ПрочитанныеПараметры.Получить("ДочерниеПроектыСтрокой"), ", ", Ложь); КонецЕсли; ИсключаемыеПроекты = Новый Массив(); - Если ЗначениеЗаполнено(ИсключаемыеПроектыСтрокой) Тогда - ИсключаемыеПроекты = СтрРазделить(ИсключаемыеПроектыСтрокой, ",", Ложь); + Если ЗначениеЗаполнено(ПрочитанныеПараметры.Получить("ИсключаемыеПроектыСтрокой")) Тогда + ИсключаемыеПроекты = СтрРазделить(ПрочитанныеПараметры.Получить("ИсключаемыеПроектыСтрокой"), ", ", Ложь); КонецЕсли; - ИсключаемыеПроекты.Добавить(СокрЛП(РодительскийПроект)); + ИсключаемыеПроекты.Добавить(СокрЛП(ПрочитанныеПараметры.Получить("РодительскийПроект"))); - Если Не ЗначениеЗаполнено(СтатусыСтрокой) Тогда + Если Не ЗначениеЗаполнено(ПрочитанныеПараметры.Получить("СтатусыСтрокой")) Тогда Статусы = СтрРазделить("RESOLVED,CLOSED", ",", Ложь); Иначе Статусы = Новый Массив(); - СтатусыВрем = СтрРазделить(ВРЕГ(СтатусыСтрокой), ",", Ложь); + СтатусыВрем = СтрРазделить(ВРЕГ(ПрочитанныеПараметры.Получить("СтатусыСтрокой")), ", ", Ложь); ВсеСтатусы = СтрРазделить("OPEN,CONFIRMED,REOPENED,RESOLVED,CLOSED", ","); Для Каждого Статус Из СтатусыВрем Цикл Если ВсеСтатусы.Найти(Статус) <> Неопределено Тогда @@ -237,25 +177,11 @@ ОшибокНет = Ложь; КонецЕсли; КонецЕсли; - - Если НЕ ЗначениеЗаполнено(Теги) Тогда - Теги = ""; + + Если НЕ ЗначениеЗаполнено(ПрочитанныеПараметры.Получить("Теги")) Тогда + ПрочитанныеПараметры.Вставить("Теги", ""); КонецЕсли; Возврат ОшибокНет; КонецФункции - -Функция ОбернутьЗначениеДляПечати(Знач Значение) - Если ЗначениеЗаполнено(Значение) Тогда - Возврат Строка(Значение); - КонецЕсли; - Возврат "<Незаполнено>"; -КонецФункции - -Функция СообщитьОбОшибке(ТекстОшибки) - - Лог.Ошибка(ТекстОшибки); - Возврат МенеджерКомандПриложения.РезультатыКоманд().ОшибкаВремениВыполнения; - -КонецФункции diff --git a/src/Классы/КомандаСгенерироватьОтчет.os b/src/Классы/КомандаСгенерироватьОтчет.os index 131555f..82db771 100644 --- a/src/Классы/КомандаСгенерироватьОтчет.os +++ b/src/Классы/КомандаСгенерироватьОтчет.os @@ -1,13 +1,19 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Служебный модуль с реализацией работы команды report +// +// (C) Maximov Valery (aka theshadowco) +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + Перем Лог; -Перем Токен; -Перем АдресСервера; -Перем РодительскийПроект; -Перем Проекты; Перем Метрики; Перем ПутьКОтчету; Перем ФорматОтчета; +Перем ПрочитанныеПараметры; + /////////////////////////////////////////////////////////////////////////////////////////////////// // Прикладной интерфейс /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -17,7 +23,7 @@ ОписаниеКоманды = Парсер.ОписаниеКоманды(ИмяКоманды, "Формирует отчет по проекту/списку проектов"); Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--token", "Токен для авторизации на сервере SonarQube"); Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--server", "Адрес сервера SonarQube (например http://my.sonar.server:9000)"); - Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--projects", "Ключ проектов, строкой через запятую (например hrm:develop,buh)"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--projects", "Ключи проектов, строкой через запятую (например hrm:develop,buh)"); Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--total-metrics", "Вывод в отчет метрик по проекту. | Нужные метрики передаются строкой через запятую. | Возможные значения (ключ - расшифровка): @@ -75,20 +81,18 @@ Лог = ДополнительныеПараметры.Лог; ОшибокНет = ПрочитатьПараметрыЗапуска(ПараметрыКоманды); Если НЕ ОшибокНет Тогда - Возврат СообщитьОбОшибке("Ошибка запуска"); + Возврат ОбщегоНазначения.СообщитьОбОшибке("Ошибка запуска"); КонецЕсли; - Если ПустаяСтрока(ПутьКОтчету) Тогда - ПутьКОтчету = ОбъединитьПути(".", "report." + НРег(ФорматОтчета)); - КонецЕсли; - + АдресСервера = ПрочитанныеПараметры.Получить("АдресСервера"); + Токен = ПрочитанныеПараметры.Получить("Токен"); + Лог.Информация("Получение информации о проектах"); ПроектыSQ = Сонар.ПолучитьПроекты(АдресСервера, Токен); + КоллекцияОтчетов = СоздатьКоллекциюОтчетов(АдресСервера); - КоллекцияОтчетов = СоздатьКоллекциюОтчетов(); Лог.Информация("Формирование отчетов по проектам"); - - КоллекцияПроектов = СтрРазделить(Проекты, ",", Ложь); + КоллекцияПроектов = СтрРазделить(ПрочитанныеПараметры.Получить("Проекты"), ",", Ложь); Для Каждого Проект Из КоллекцияПроектов Цикл Лог.Информация(" Формирование отчета для проекта `%1`", Проект); @@ -115,112 +119,39 @@ Функция ПрочитатьПараметрыЗапуска(ПараметрыКоманды) - МаксимальноеКоличествоСтатусов = 5; - ОшибокНет = Истина; - - Токен = ПараметрыКоманды["--token"]; - АдресСервера = ПараметрыКоманды["--server"]; - Проекты = ПараметрыКоманды["--projects"]; - Метрики = ПараметрыКоманды["--total-metrics"]; - ПутьКОтчету = ПараметрыКоманды["--report-path"]; - ФорматОтчета = ПараметрыКоманды["--report-format"]; + ПрочитанныеПараметры = ОбщегоНазначения.ПрочитатьПараметрыЗапуска(ПараметрыКоманды, Истина); + ОшибокНет = ПрочитанныеПараметры.Получить("ОшибокНет"); - ПутьККонфигурационномуФайлу = ПараметрыКоманды["--cfg-file"]; - Если ПутьККонфигурационномуФайлу <> Неопределено Тогда - - Файл = Новый Файл(ПутьККонфигурационномуФайлу); - Если Файл.Существует() Тогда - ТекстовыйДокумент = Новый ТекстовыйДокумент(); - ТекстовыйДокумент.Прочитать(ПутьККонфигурационномуФайлу); - Лог.Отладка("Содержимое конфигурационного файла: %1%2", Символы.ПС, ТекстовыйДокумент.ПолучитьТекст()); - JSON = Новый ЧтениеJSON(); - JSON.УстановитьСтроку(ТекстовыйДокумент.ПолучитьТекст()); - ПараметрыИзФайла = ПрочитатьJSON(JSON, Истина); - Если Токен = Неопределено Тогда - Токен = ПараметрыИзФайла.Получить("--token"); - КонецЕсли; - Если АдресСервера = Неопределено Тогда - АдресСервера = ПараметрыИзФайла.Получить("--server"); - КонецЕсли; - Если Проекты = Неопределено Тогда - Проекты = ПараметрыИзФайла.Получить("--projects"); - КонецЕсли; - Если Метрики = Неопределено Тогда - Метрики = ПараметрыИзФайла.Получить("--total-metrics"); - КонецЕсли; - Если ПутьКОтчету = Неопределено Тогда - ПутьКОтчету = ПараметрыИзФайла.Получить("--report-path"); - КонецЕсли; - Если ФорматОтчета = Неопределено Тогда - ФорматОтчета = ПараметрыИзФайла.Получить("--report-format"); - КонецЕсли; - Иначе - Лог.Ошибка("Конфигурационный файл по пути `%1` не обнаружен", ОбернутьЗначениеДляПечати(ПутьККонфигурационномуФайлу)); - ОшибокНет = Ложь; - КонецЕсли; - - КонецЕсли; - - Лог.Отладка("Прочитанные параметры:"); - Лог.Отладка(" Токен = `%1`", ОбернутьЗначениеДляПечати(Токен)); - Лог.Отладка(" Адрес сервера = `%1`", ОбернутьЗначениеДляПечати(АдресСервера)); - Лог.Отладка(" Ключи проектов = `%1`", ОбернутьЗначениеДляПечати(Проекты)); - Лог.Отладка(" Метрики проекта = `%1`", ОбернутьЗначениеДляПечати(Метрики)); - Лог.Отладка(" Путь к отчету = `%1`", ОбернутьЗначениеДляПечати(ПутьКОтчету)); - Лог.Отладка(" Формат отчета = `%1`", ОбернутьЗначениеДляПечати(ФорматОтчета)); - - Если Не ЗначениеЗаполнено(Токен) Тогда - Лог.Ошибка("Не указан токен для авторизации"); - ОшибокНет = Ложь; - КонецЕсли; - - Если Не ЗначениеЗаполнено(АдресСервера) Тогда - Лог.Ошибка("Не указан адрес сервера SonarQube"); - ОшибокНет = Ложь; - КонецЕсли; - - Если Не ЗначениеЗаполнено(Проекты) Тогда + Если Не ЗначениеЗаполнено(ПрочитанныеПараметры.Получить("Проекты")) Тогда Лог.Ошибка("Не указан ключ(-и) проекта(-ов)"); ОшибокНет = Ложь; КонецЕсли; - Метрики = ПолучитьПравильныеМетрики(Метрики, ОшибокНет); - - Если Не ЗначениеЗаполнено(ПутьКОтчету) Тогда - ПутьКОтчету = ""; - КонецЕсли; + Метрики = ПолучитьПравильныеМетрики(ПрочитанныеПараметры.Получить("Метрики"), ОшибокНет); + ПутьКОтчету = ПрочитанныеПараметры.Получить("ПутьКОтчету"); + ФорматОтчета = ПрочитанныеПараметры.Получить("ФорматОтчета"); Если Не ЗначениеЗаполнено(ФорматОтчета) Тогда ФорматОтчета = "JSON"; Иначе ФорматОтчета = ПолучитьПравильныйФорматОтчета(ФорматОтчета, ОшибокНет); КонецЕсли; + + Если Не ЗначениеЗаполнено(ПутьКОтчету) Тогда + ПутьКОтчету = ОбъединитьПути(".", "report." + НРег(ФорматОтчета)); + КонецЕсли; Возврат ОшибокНет; КонецФункции -Функция ОбернутьЗначениеДляПечати(Знач Значение) - Если ЗначениеЗаполнено(Значение) Тогда - Возврат Строка(Значение); - КонецЕсли; - Возврат "<Незаполнено>"; -КонецФункции - -Функция СообщитьОбОшибке(ТекстОшибки) - - Лог.Ошибка(ТекстОшибки); - Возврат МенеджерКомандПриложения.РезультатыКоманд().ОшибкаВремениВыполнения; - -КонецФункции - Функция ПолучитьПравильныйФорматОтчета(Знач ВыбранныйФорматОтчета, ОшибокНет) ВРЕГВыбранныйФорматОтчета = ВРЕГ(ВыбранныйФорматОтчета); Если НЕ (ВРЕГВыбранныйФорматОтчета = "HTML" ИЛИ ВРЕГВыбранныйФорматОтчета = "JSON") Тогда ОшибокНет = Ложь; - Лог.Ошибка("Указан неизвестный формат отчета `%1`", ОбернутьЗначениеДляПечати(ВыбранныйФорматОтчета)); + Лог.Ошибка("Указан неизвестный формат отчета `%1`", ОбщегоНазначения.ОбернутьЗначениеДляПечати(ВыбранныйФорматОтчета)); КонецЕсли; @@ -243,7 +174,7 @@ ПравильныеМетрики.Вставить(СокрЛП(Метрика), 0); Иначе ОшибокНет = Ложь; - Лог.Ошибка("Указана неизвестная метрика `%1`", ОбернутьЗначениеДляПечати(Метрика)); + Лог.Ошибка("Указана неизвестная метрика `%1`", ОбщегоНазначения.ОбернутьЗначениеДляПечати(Метрика)); КонецЕсли; КонецЦикла; КонецЕсли; @@ -252,7 +183,7 @@ КонецФункции -Функция СоздатьКоллекциюОтчетов() +Функция СоздатьКоллекциюОтчетов(АдресСервера) Результат = Новый Структура(); Результат.Вставить("ДатаФормирования", ТекущаяДата()); diff --git a/src/Классы/КомандаСгенерироватьОтчетПоПользователям.os b/src/Классы/КомандаСгенерироватьОтчетПоПользователям.os new file mode 100644 index 0000000..b21b869 --- /dev/null +++ b/src/Классы/КомандаСгенерироватьОтчетПоПользователям.os @@ -0,0 +1,252 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Служебный модуль с реализацией работы команды report +// +// (C) Maximov Valery (aka theshadowco) +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +Перем Лог; + +Перем ПутьКОтчету; +Перем ФорматОтчета; +Перем СтатусыСтрокой; + +Перем ПрочитанныеПараметры; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Прикладной интерфейс +/////////////////////////////////////////////////////////////////////////////////////////////////// + +Процедура ЗарегистрироватьКоманду(Знач ИмяКоманды, Знач Парсер) Экспорт + + ОписаниеКоманды = Парсер.ОписаниеКоманды(ИмяКоманды, "Формирует сводный отчет по наличию замечаний пользователей"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--token", "Токен для авторизации на сервере SonarQube"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--server", "Адрес сервера SonarQube (например http://my.sonar.server:9000)"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--projects", "Ключи проектов, строкой через запятую (например hrm:develop,buh)"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--statuses", "Отбор замечаний только соответствующих статусов. + | Необходимые статусы необходимо передавать строкой через запятую. + | Возможные значения: + | OPEN - открытые + | CONFIRMED - подтвержденные: + | REOPENED - переоткрытые + | RESOLVED - решенные + | CLOSED - закрытые + | + | По умолчанию выбираются только OPEN, CONFIRMED и REOPENED"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--report-path", "Путь для сохранения отчета"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--report-format", "Формат сохраняемого отчета. + | Возможные варианнты: + | HTML - создает html - страницу + | JSON - выгружает файл json + | + | По умолчанию используется формат JSON"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--cfg-file", "Путь к конфигурационному файлу в формате json (utf-8), свойства объекта соответствуют ключам запуска. + | Пример конфигурационного файла находится в каталоге examples"); + + Парсер.ДобавитьКоманду(ОписаниеКоманды); + +КонецПроцедуры + +// Выполняет логику команды +// +// Параметры: +// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений +// ДополнительныеПараметры - Соответствие - (необязательно) дополнительные параметры +// +Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач ДополнительныеПараметры = Неопределено) Экспорт + + Лог = ДополнительныеПараметры.Лог; + ОшибокНет = ПрочитатьПараметрыЗапуска(ПараметрыКоманды); + Если НЕ ОшибокНет Тогда + Возврат ОбщегоНазначения.СообщитьОбОшибке("Ошибка запуска"); + КонецЕсли; + + АдресСервера = ПрочитанныеПараметры.Получить("АдресСервера"); + Токен = ПрочитанныеПараметры.Получить("Токен"); + + Лог.Информация("Получение информации о проектах"); + ПроектыSQ = Сонар.ПолучитьПроекты(АдресСервера, Токен); + КоллекцияОтчетов = СоздатьКоллекциюОтчетов(АдресСервера); + + Лог.Информация("Формирование отчетов по проектам"); + + Проекты = ПрочитанныеПараметры.Получить("Проекты"); + Если Не ЗначениеЗаполнено(Проекты) Тогда + Проекты = ""; + КонецЕсли; + + КоллекцияПроектов = СтрРазделить(Проекты, ",", Ложь); + Замечания = Неопределено; + Для Каждого ОписаниеПроекта Из ПроектыSQ Цикл + + Если КоллекцияПроектов.Количество() И КоллекцияПроектов.Найти(ОписаниеПроекта.Значение.Код) = Неопределено Тогда + Продолжить; + КонецЕсли; + + Лог.Информация(" Формирование отчета для проекта `%1`", ОписаниеПроекта.Значение.Код); + Замечания = Сонар.ПолучитьСводнуюИнформациюПоЗамечаниямиПроекта(АдресСервера, Токен, ОписаниеПроекта.Значение, СтатусыСтрокой, Замечания); + + КонецЦикла; + + КоллекцияОтчетов.Замечания = Замечания; + КоллекцияОтчетов.Количество = КоллекцияОтчетов.Замечания.Количество(); + + Лог.Информация("Сохранение отчетов в файл '%1'", ПутьКОтчету); + СформироватьОтчет(КоллекцияОтчетов); + + Возврат МенеджерКомандПриложения.РезультатыКоманд().Успех; + +КонецФункции + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +Функция ПрочитатьПараметрыЗапуска(ПараметрыКоманды) + + ПрочитанныеПараметры = ОбщегоНазначения.ПрочитатьПараметрыЗапуска(ПараметрыКоманды, Истина); + ОшибокНет = ПрочитанныеПараметры.Получить("ОшибокНет"); + МаксимальноеКоличествоСтатусов = 5; + + Если Не ЗначениеЗаполнено(ПрочитанныеПараметры.Получить("СтатусыСтрокой")) Тогда + СтатусыСтрокой = "OPEN,CONFIRMED,REOPENED"; + Иначе + Статусы = Новый Массив(); + СтатусыВрем = СтрРазделить(ВРЕГ(ПрочитанныеПараметры.Получить("СтатусыСтрокой")), ",", Ложь); + ВсеСтатусы = СтрРазделить("OPEN,CONFIRMED,REOPENED,RESOLVED,CLOSED", ","); + Для Каждого Статус Из СтатусыВрем Цикл + Если ВсеСтатусы.Найти(Статус) <> Неопределено Тогда + Статусы.Добавить(Статус); + Иначе + Лог.Ошибка("Неопознанный статус `%1`", Статус); + КонецЕсли; + КонецЦикла; + Если Статусы.Количество() = 0 Тогда + Лог.Ошибка("Указанный фильтр по статусам не содержит корректных значений"); + ОшибокНет = Ложь; + КонецЕсли; + СтатусыСтрокой = СтрСоединить(Статусы, ","); + КонецЕсли; + + ПутьКОтчету = ПрочитанныеПараметры.Получить("ПутьКОтчету"); + ФорматОтчета = ПрочитанныеПараметры.Получить("ФорматОтчета"); + + Если Не ЗначениеЗаполнено(ФорматОтчета) Тогда + ФорматОтчета = "JSON"; + Иначе + ФорматОтчета = ПолучитьПравильныйФорматОтчета(ФорматОтчета, ОшибокНет); + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПутьКОтчету) Тогда + ПутьКОтчету = ОбъединитьПути(".", "report." + НРег(ФорматОтчета)); + КонецЕсли; + + Возврат ОшибокНет; + +КонецФункции + +Функция ПолучитьПравильныйФорматОтчета(Знач ВыбранныйФорматОтчета, ОшибокНет) + + ВРЕГВыбранныйФорматОтчета = ВРЕГ(ВыбранныйФорматОтчета); + Если ВРЕГВыбранныйФорматОтчета <> "JSON" Тогда + + ОшибокНет = Ложь; + Лог.Ошибка("Указан неизвестный формат отчета `%1`", ОбщегоНазначения.ОбернутьЗначениеДляПечати(ВыбранныйФорматОтчета)); + + КонецЕсли; + + Возврат ВРЕГВыбранныйФорматОтчета; + +КонецФункции + +Функция СоздатьКоллекциюОтчетов(АдресСервера) + + Результат = Новый Структура(); + Результат.Вставить("ДатаФормирования", ТекущаяДата()); + Результат.Вставить("СерверSonarQube", АдресСервера); + Результат.Вставить("Количество", 0); + Результат.Вставить("Замечания", Неопределено); + + Возврат Результат; + +КонецФункции + +Процедура СформироватьОтчет(КоллекцияОтчетов) + + Если ФорматОтчета = "JSON" Тогда + ЗаписьJSON = Новый ЗаписьJSON(); + ЗаписьJSON.ОткрытьФайл(ПутьКОтчету); + КоллекцияОтчетов.Замечания = ТаблицаЗначенийВМассив(КоллекцияОтчетов.Замечания); + ЗаписатьJSON(ЗаписьJSON, КоллекцияОтчетов); + ЗаписьJSON.Закрыть(); + КонецЕсли; + +КонецПроцедуры + +Функция ТаблицаЗначенийВМассив(ТаблицаЗначений, РезультатВФиксированнуюКоллекцию = Ложь) + + МассивРезультат = Новый Массив(); + СтруктураСтрокой = ""; + НоваяСтрока = Неопределено; + + КолонкиСТипомТЧ = Новый Массив; + + Если ТипЗнч(ТаблицаЗначений) = Тип("ТаблицаЗначений") Тогда + + КолонкиТаблицы = ТаблицаЗначений.Колонки; + + ИначеЕсли ТипЗнч(ТаблицаЗначений) = Тип("Массив") И ТипЗнч(ТаблицаЗначений[0]) = Тип("СтрокаТаблицыЗначений") Тогда + + КолонкиТаблицы = ТаблицаЗначений[0].Владелец().Колонки; + + Иначе + + ВызватьИсключение "Не поддерживаемый тип параметра"; + + КонецЕсли; + + Если ТаблицаЗначений.Количество() = 0 Тогда + + Возврат МассивРезультат; + + КонецЕсли; + + Для Каждого Колонка Из КолонкиТаблицы Цикл + + СтруктураСтрокой = СтруктураСтрокой + ?(ПустаяСтрока(СтруктураСтрокой), "", ",") + Колонка.Имя ; + + КонецЦикла; + + Для Каждого Строка Из ТаблицаЗначений Цикл + + НоваяСтрока = Новый Структура(СтруктураСтрокой); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка); + + Для Каждого КолонкаСТипомТЧ Из КолонкиСТипомТЧ Цикл + + Если ТипЗнч(Строка[КолонкаСТипомТЧ]) = Тип("ТаблицаЗначений") Тогда + + НоваяСтрока[КолонкаСТипомТЧ] = ТаблицаЗначенийВМассив(Строка[КолонкаСТипомТЧ], РезультатВФиксированнуюКоллекцию); + + КонецЕсли; + + КонецЦикла; + + Если РезультатВФиксированнуюКоллекцию Тогда + + НоваяСтрока = Новый ФиксированнаяСтруктура(НоваяСтрока); + + КонецЕсли; + + МассивРезультат.Добавить(НоваяСтрока); + + КонецЦикла; + + Если РезультатВФиксированнуюКоллекцию Тогда + + МассивРезультат = Новый ФиксированныйМассив(МассивРезультат); + + КонецЕсли; + + Возврат МассивРезультат; + +КонецФункции // ТаблицаЗначенийВМассив diff --git a/src/Модули/ОбщегоНазначения.os b/src/Модули/ОбщегоНазначения.os new file mode 100644 index 0000000..78aa74b --- /dev/null +++ b/src/Модули/ОбщегоНазначения.os @@ -0,0 +1,148 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Служебный модуль с общими методами приложения +// +// (C) Maximov Valery (aka theshadowco) +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// ОбернутьЗначениеДляПечати +// Формирует строку из значения для удобной печати +// Параметры: +// Значение - Произвольное - Значение, которое необходимо преобразовать в строку для последующей печати +// +// Возвращаемое значение: +// Строка - Преобразованное в строку входное значение. Если значение не заполнено, то вернется "<Незаполнено>" +// +Функция ОбернутьЗначениеДляПечати(Знач Значение) Экспорт + + Если ЗначениеЗаполнено(Значение) Тогда + Возврат Строка(Значение); + КонецЕсли; + + Возврат "<Незаполнено>"; + +КонецФункции + +// ПрочитатьПараметрыЗапуска +// Читает входные параметры включа конфигурационный файл +// Параметры: +// ПараметрыКоманды - Соответствие - Входные параметры приложения +// ВыполнятьПроверкуАвторизацииСразу - Булево - Выполнение проверки корректности параметров авторизации +// +// Возвращаемое значение: +// Соответствие - Ключи и значения параметров запуска +// +Функция ПрочитатьПараметрыЗапуска(ПараметрыКоманды, ВыполнятьПроверкуАвторизацииСразу) Экспорт + + Лог = Логирование.ПолучитьЛог(ПараметрыСистемы.ИмяЛогаСистемы()); + + ПрочитанныеПараметры = Новый Соответствие(); + ОшибокНет = Истина; + + ВозможныеКлючи = ВозможныеКлючи(); + Для Каждого ВозможныйКлюч Из ВозможныеКлючи Цикл + + ПрочитанныеПараметры.Вставить(ВозможныйКлюч.Ключ, ПараметрыКоманды.Получить(ВозможныйКлюч.Значение)); + + КонецЦикла; + + ПутьККонфигурационномуФайлу = ПараметрыКоманды["--cfg-file"]; + + Если ПутьККонфигурационномуФайлу <> Неопределено Тогда + + Файл = Новый Файл(ПутьККонфигурационномуФайлу); + Если Файл.Существует() Тогда + + ТекстовыйДокумент = Новый ТекстовыйДокумент(); + ТекстовыйДокумент.Прочитать(ПутьККонфигурационномуФайлу); + Лог.Отладка("Содержимое конфигурационного файла: %1%2", Символы.ПС, ТекстовыйДокумент.ПолучитьТекст()); + JSON = Новый ЧтениеJSON(); + JSON.УстановитьСтроку(ТекстовыйДокумент.ПолучитьТекст()); + ПараметрыИзФайла = ПрочитатьJSON(JSON, Истина); + + Для Каждого ВозможныйКлюч Из ВозможныеКлючи Цикл + + ЗначениеИзФайла = ПараметрыИзФайла.Получить(ВозможныйКлюч.Значение); + Если ЗначениеИзФайла <> Неопределено И ПрочитанныеПараметры.Получить(ВозможныйКлюч.Ключ) = Неопределено Тогда + ПрочитанныеПараметры.Вставить(ВозможныйКлюч.Ключ, ЗначениеИзФайла); + КонецЕсли; + + КонецЦикла; + + Иначе + + Лог.Ошибка("Конфигурационный файл по пути `%1` не обнаружен", ОбернутьЗначениеДляПечати(ПутьККонфигурационномуФайлу)); + ОшибокНет = ЛОЖЬ; + + КонецЕсли; + + КонецЕсли; + + Лог.Отладка("Прочитанные параметры:"); + Для Каждого ПрочитанныйПараметр Из ПрочитанныеПараметры Цикл + + Лог.Отладка(" %2 = `%1`", ОбернутьЗначениеДляПечати(ПрочитанныйПараметр.Значение), ПрочитанныйПараметр.Ключ); + + КонецЦикла; + + Если ВыполнятьПроверкуАвторизацииСразу Тогда + + Если Не ЗначениеЗаполнено(ПрочитанныеПараметры.Получить("Токен")) Тогда + + Лог.Ошибка("Не указан токен для авторизации"); + ОшибокНет = Ложь; + + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПрочитанныеПараметры.Получить("АдресСервера")) Тогда + + Лог.Ошибка("Не указан адрес сервера SonarQube"); + ОшибокНет = Ложь; + + КонецЕсли; + + КонецЕсли; + + ПрочитанныеПараметры.Вставить("ОшибокНет", ОшибокНет); + + Возврат ПрочитанныеПараметры; + +КонецФункции + +// СообщитьОбОшибке +// Выводит сообщение об ошибке и возвращает статус ошибочного завершения приложения +// Параметры: +// ТекстОшибки - Строка - Выводимое сообщение об ошибке +// +// Возвращаемое значение: +// Число - Код ошибки выполнения +// +Функция СообщитьОбОшибке(ТекстОшибки) Экспорт + + Лог = Логирование.ПолучитьЛог(ПараметрыСистемы.ИмяЛогаСистемы()); + Лог.Ошибка(ТекстОшибки); + Возврат МенеджерКомандПриложения.РезультатыКоманд().ОшибкаВремениВыполнения; + +КонецФункции + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +Функция ВозможныеКлючи() + + ВозможныеКлючи = Новый Структура(); + ВозможныеКлючи.Вставить("Токен", "--token"); + ВозможныеКлючи.Вставить("АдресСервера", "--server"); + ВозможныеКлючи.Вставить("РодительскийПроект", "--parent-project"); + ВозможныеКлючи.Вставить("ИсключаемыеПроектыСтрокой", "--exclude-projects"); + ВозможныеКлючи.Вставить("СтатусыСтрокой", "--statuses"); + ВозможныеКлючи.Вставить("Теги", "--tags"); + ВозможныеКлючи.Вставить("ИзEDTВКонфигуратор", "--edt2cfg"); + ВозможныеКлючи.Вставить("Проекты", "--projects"); + ВозможныеКлючи.Вставить("Метрики", "--total-metrics"); + ВозможныеКлючи.Вставить("ПутьКОтчету", "--report-path"); + ВозможныеКлючи.Вставить("ФорматОтчета", "--report-format"); + + Возврат ВозможныеКлючи; + +КонецФункции diff --git a/src/Модули/ПараметрыСистемы.os b/src/Модули/ПараметрыСистемы.os index d84668d..97bf0d6 100644 --- a/src/Модули/ПараметрыСистемы.os +++ b/src/Модули/ПараметрыСистемы.os @@ -50,6 +50,7 @@ ВозможныеКомандыПриложения.Вставить("ПоказатьВерсию", "version"); ВозможныеКомандыПриложения.Вставить("ЗакрытьИшузы", "issue-resolver"); ВозможныеКомандыПриложения.Вставить("СгенерироватьОтчет", "report"); + ВозможныеКомандыПриложения.Вставить("СгенерироватьОтчетПоПользователям", "usr-report"); ВозможныеКомандыПриложения = Новый ФиксированнаяСтруктура(ВозможныеКомандыПриложения); @@ -61,12 +62,11 @@ Процедура ПриРегистрацииКомандПриложения(Знач КлассыРеализацииКоманд) Экспорт - КлассыРеализацииКоманд[ВозможныеКоманды().Помощь] = "КомандаСправкаПоПараметрам"; - КлассыРеализацииКоманд[ИмяКомандыВерсия()] = "КомандаVersion"; - КлассыРеализацииКоманд[ВозможныеКоманды().ЗакрытьИшузы] = "КомандаЗакрытьИшузы"; - КлассыРеализацииКоманд[ВозможныеКоманды().СгенерироватьОтчет] = "КомандаСгенерироватьОтчет"; - //... - //КлассыРеализацииКоманд["<имя команды>"] = "<КлассРеализации>"; + КлассыРеализацииКоманд[ВозможныеКоманды().Помощь] = "КомандаСправкаПоПараметрам"; + КлассыРеализацииКоманд[ИмяКомандыВерсия()] = "КомандаVersion"; + КлассыРеализацииКоманд[ВозможныеКоманды().ЗакрытьИшузы] = "КомандаЗакрытьИшузы"; + КлассыРеализацииКоманд[ВозможныеКоманды().СгенерироватьОтчет] = "КомандаСгенерироватьОтчет"; + КлассыРеализацииКоманд[ВозможныеКоманды().СгенерироватьОтчетПоПользователям] = "КомандаСгенерироватьОтчетПоПользователям"; КонецПроцедуры // ПриРегистрацииКомандПриложения diff --git a/src/Модули/Сонар.os b/src/Модули/Сонар.os index fee2007..25a87ea 100644 --- a/src/Модули/Сонар.os +++ b/src/Модули/Сонар.os @@ -176,6 +176,127 @@ КонецФункции +// ПолучитьСводнуюИнформациюПоЗамечаниямиПроекта +// Возвращает свернутую таблицу с пользователями и их замечаниями на проекте проекта +// Параметры: +// АдресСервера - Строка - Адрес (хост) сервера SonarQube +// Токен - Строка - Токен пользователя, от имени которого выполняются запросы к API +// ОписаниеПроекта - Структура - Описание проекта SonarQube +// * Идентификатор - Строка - Идентификатор проекта +// * Код - Строка - Код (Ключ) проекта +// СтатусыСтрокой - Строка - Строка с идентификаторами статусов замечаний +// Замечания - ТаблицаЗначений - Таблица со сводной информацией замечаний, аналогичная выходной. Используется при необходимости дополнять для нескольких проектов +// +// Возвращаемое значение: +// ТаблицаЗначения - Содвная таблица с замечаниями +// * КлючПроекта - Строка - Ключ проекта sonarqube +// * Статус - Строка - Статус замечания +// * Автор - Строка - Пользователь, автор замечания по git (email) +// * Отвественный - Строка, NULL - Пользователь, на которого назначено замечание (учетная запись) +// * Правило - Строка - Ключ правила +// * Критичность - Строка - Критичность замечания +// * Тип - Строка - Тип замечания +// * Время - Число - Время на исправление замечания (в минутах) +// * Количество - Число - Количество замечаний +// +Функция ПолучитьСводнуюИнформациюПоЗамечаниямиПроекта(АдресСервера, Токен, ОписаниеПроекта, СтатусыСтрокой, Замечания = Неопределено) Экспорт + + КлючиКомпонентов = ПолучитьКлючиКомпонентов(АдресСервера, Токен, ОписаниеПроекта.Код, СтатусыСтрокой); + URLШаблон = "issues/search?ps=500&componentKeys=%1%2"; + Если Не ПустаяСтрока(СтатусыСтрокой) Тогда + URLШаблон = URLШаблон + "&statuses=" + СтатусыСтрокой; + КонецЕсли; + URLШаблон = URLШаблон + "&p="; + + КоличествоКомпонентов = КлючиКомпонентов.Количество(); + + Если Замечания = Неопределено Тогда + Замечания = Новый ТаблицаЗначений(); + Замечания.Колонки.Добавить("КлючПроекта"); + Замечания.Колонки.Добавить("Статус"); + Замечания.Колонки.Добавить("Автор"); + Замечания.Колонки.Добавить("Отвественный"); + Замечания.Колонки.Добавить("Правило"); + Замечания.Колонки.Добавить("Критичность"); + Замечания.Колонки.Добавить("Тип"); + Замечания.Колонки.Добавить("Время"); + Замечания.Колонки.Добавить("Количество"); + КонецЕсли; + + Для Ит = 0 По КоличествоКомпонентов - 1 Цикл + КлючКомпонента = КлючиКомпонентов[Ит]; + + НомерСтраницы = 1; + URL = СтрШаблон(URLШаблон, КлючКомпонента, ""); + Пока Истина Цикл + + Ответ = ВыполнитьЗапрос(АдресСервера, Токен, URL + Формат(НомерСтраницы, "ЧГ="), "GET"); + Если Ответ.total > МаксимальныйРазмерПорцииДанных Тогда + // прочитаем компоненты, перенесем их в общий список, а по текущем прочтем только те, что висят именно на нем + КлючиДочернихКомпонентов = ПолучитьКлючиКомпонентов(АдресСервера, Токен, КлючКомпонента, СтатусыСтрокой, Ложь); + Для Каждого КлючДочернегоКомпонента Из КлючиДочернихКомпонентов Цикл + КлючиКомпонентов.Добавить(КлючДочернегоКомпонента); + КонецЦикла; + КоличествоКомпонентов = КлючиКомпонентов.Количество(); + URL = СтрШаблон(URLШаблон, КлючКомпонента, "&onComponentOnly=true"); + Ответ = ВыполнитьЗапрос(АдресСервера, Токен, URL + Формат(НомерСтраницы, "ЧГ="), "GET"); + КонецЕсли; + + Для Каждого ОписаниеОшибки Из Ответ.issues Цикл + + Замечание = Замечания.Добавить(); + Замечание.КлючПроекта = ОписаниеПроекта.Код; + Замечание.Автор = ОписаниеОшибки.author; + Если Не ОписаниеОшибки.Свойство("assignee") Тогда + Замечание.Отвественный = NULL; + Иначе + Замечание.Отвественный = ОписаниеОшибки.assignee; + КонецЕсли; + + Замечание.Правило = ОписаниеОшибки.rule; + Замечание.Статус = ОписаниеОшибки.status; + Замечание.Критичность = ОписаниеОшибки.severity; + Замечание.Тип = ОписаниеОшибки.type; + Замечание.Количество = 1; + Замечание.Время = 0; + + Если ОписаниеОшибки.Свойство("debt") Тогда + ВремяСтрокой = СтрЗаменить(ОписаниеОшибки.debt, "min", ""); + Поз = СтрНайти(ВремяСтрокой, "h"); + Если Поз <> СтрДлина(ВремяСтрокой) Тогда + ВремяСтрокой = СтрЗаменить(ВремяСтрокой, "h", "*60+"); + Иначе + ВремяСтрокой = СтрЗаменить(ВремяСтрокой, "h", "*60"); + КонецЕсли; + + Поз = СтрНайти(ВремяСтрокой, "d"); + Если Поз <> СтрДлина(ВремяСтрокой) Тогда + ВремяСтрокой = СтрЗаменить(ВремяСтрокой, "d", "*480+"); // рабочие дни + Иначе + ВремяСтрокой = СтрЗаменить(ВремяСтрокой, "d", "*480"); + КонецЕсли; + + Замечание.Время = Вычислить(ВремяСтрокой); + + КонецЕсли; + КонецЦикла; + + Если БольшеНетДанных(Ответ) Тогда + Прервать; + КонецЕсли; + + НомерСтраницы = НомерСтраницы + 1; + + КонецЦикла; + + КонецЦикла; + + Замечания.Свернуть("КлючПроекта, Автор, Отвественный, Правило, Критичность, Тип, Статус", "Время, Количество"); + + Возврат Замечания; + +КонецФункции + // ЗаполнитьКоличествоОдинаковыхЗамечанийПроекта // По сформированному набору замечаний дополняет общее количество замечаний со всеми статусами с тем же хэшем // Параметры: @@ -474,7 +595,6 @@ HTTPЗапрос = Новый HTTPЗапрос; HTTPЗапрос.АдресРесурса = Префикс + "api/" + URL; - Сообщить(HTTPЗапрос.АдресРесурса); HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json"); HTTP = Новый HTTPСоединение(АдресСервера, , Токен); @@ -485,6 +605,7 @@ КонецЕсли; Если ОтветHTTP.КодСостояния = 200 Тогда + // Сообщить(ОтветHTTP.ПолучитьТелоКакСтроку()); json = Новый ЧтениеJSON(); json.УстановитьСтроку(ОтветHTTP.ПолучитьТелоКакСтроку()); Возврат ПрочитатьJson(json);