commit 5b168b15515f6645e90994be6d65d4a392c93e3d Author: Maximov Valery Date: Fri Jan 18 14:19:25 2019 +0300 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec6c24e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +*.log +*.ospx diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..556f7c9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018-2019 Maximov Valery aka theshadowco + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6a5beaf --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# Sonar Helper + +Предоставляет набор утилит, помогающих при работе с SonarQube. + +При работе используется REST API SonarQube. + +Обращаю внимание, что для выполнения большинства операций необходимы расширенные права пользователя. + +## Возможности + +На данный момент предоставляются следующие инструменты: + +### Закрытие замечаний, привнесенных родительским проектом + +Часто возникают ситуации, когда в разных проектах используется общая кодовая база и есть потребность исключить замечания родительского проекта, т.к. исправление их в дочернем самостоятельно не планируется. Переносить руками все замечания достаточно проблематично. + +Для закрытия замечаний необходимо вызвать команду `issue-resolver` и передать ей информацию для авторизации, данные родительского и дочерних проектов. diff --git a/examples/example.cfg-file.json b/examples/example.cfg-file.json new file mode 100644 index 0000000..004cae1 --- /dev/null +++ b/examples/example.cfg-file.json @@ -0,0 +1,9 @@ +{ + "--token": "2ef785ca946170b7086668132175eb01386943a1", + "--server": "http://my.sonar.server:9000", + "--parent-project": "zarplataiupravleniepersonalomkorp:develop", + "--child-projects": "zarplataiupravleniepersonalomkorp:master,zarplataiupravleniepersonalomprof:develop", + "--exclude-projects": "upravleniepredpriiatiem:develop", + "--statuses": "CLOSED", + "--edt2cfg": false +} diff --git a/packagedef b/packagedef new file mode 100644 index 0000000..8070ef4 --- /dev/null +++ b/packagedef @@ -0,0 +1,17 @@ +ПутьКСценариюПараметров = ОбъединитьПути(ТекущийСценарий().Каталог, "src", "Модули", "ПараметрыСистемы.os"); +ПараметрыСистемы_ЛокальнаяВерсия = ЗагрузитьСценарий(ПутьКСценариюПараметров); + +Описание.Имя(ПараметрыСистемы_ЛокальнаяВерсия.ИмяПродукта()) + .Версия(ПараметрыСистемы_ЛокальнаяВерсия.ВерсияПродукта()) + .ВерсияСреды("1.0.20") + .ЗависитОт("logos", "1.2.0") + .ЗависитОт("cmdline", "1.0.0") + .ЗависитОт("1commands", "1.3.5") + + .ВключитьФайл("src") + .ВключитьФайл("packagedef") + .ВключитьФайл("readme.md") + .ВключитьФайл("LICENSE") + .ВключитьФайл("examples") + + .ИсполняемыйФайл("src/main.os", "sonar-helper") diff --git a/src/main.os b/src/main.os new file mode 100644 index 0000000..4ca017c --- /dev/null +++ b/src/main.os @@ -0,0 +1,109 @@ +/////////////////////////////////////////////////////////////////// +// +// Рекомендованная структура модуля точки входа приложения +// +/////////////////////////////////////////////////////////////////// + +#Использовать cmdline +#Использовать logos +#Использовать 1commands + +#Использовать "." + +/////////////////////////////////////////////////////////////////// + +Перем Лог; + +/////////////////////////////////////////////////////////////////// + +Процедура Инициализация() + + Лог = Логирование.ПолучитьЛог(ПараметрыСистемы.ИмяЛогаСистемы()); + МенеджерКомандПриложения.РегистраторКоманд(ПараметрыСистемы); + +КонецПроцедуры + +Функция ВыполнениеКоманды() + + ПараметрыЗапуска = РазобратьАргументыКоманднойСтроки(); + + Если ПараметрыЗапуска = Неопределено ИЛИ ПараметрыЗапуска.Количество() = 0 Тогда + + ВывестиВерсию(); + Лог.Ошибка("Некорректные аргументы командной строки"); + МенеджерКомандПриложения.ПоказатьСправкуПоКомандам(); + Возврат МенеджерКомандПриложения.РезультатыКоманд().ОшибкаВремениВыполнения; + + КонецЕсли; + + Команда = ""; + ЗначенияПараметров = Неопределено; + + Если ТипЗнч(ПараметрыЗапуска) = Тип("Структура") Тогда + + // это команда + Команда = ПараметрыЗапуска.Команда; + ЗначенияПараметров = ПараметрыЗапуска.ЗначенияПараметров; + + Лог.Отладка("Выполняю команду продукта %1", Команда); + + ИначеЕсли ЗначениеЗаполнено(ПараметрыСистемы.ИмяКомандыПоУмолчанию()) Тогда + + // это команда по-умолчанию + Команда = ПараметрыСистемы.ИмяКомандыПоУмолчанию(); + ЗначенияПараметров = ПараметрыЗапуска; + + Лог.Отладка("Выполняю команду продукта по умолчанию %1", Команда); + + Иначе + + ВызватьИсключение "Некорректно настроено имя команды по-умолчанию."; + + КонецЕсли; + + Если Команда <> ПараметрыСистемы.ИмяКомандыВерсия() Тогда + ВывестиВерсию(); + КонецЕсли; + + // ДополнитьЗначенияПараметров(Команда, ЗначенияПараметров); + + Возврат МенеджерКомандПриложения.ВыполнитьКоманду(Команда, ЗначенияПараметров); + +КонецФункции // ВыполнениеКоманды() + +Процедура ВывестиВерсию() + + Сообщить(СтрШаблон("%1 v%2", ПараметрыСистемы.ИмяПродукта(), ПараметрыСистемы.ВерсияПродукта())); + +КонецПроцедуры // ВывестиВерсию() + +Функция РазобратьАргументыКоманднойСтроки() + + Парсер = ПолучитьПарсерКоманднойСтроки(); + Возврат Парсер.Разобрать(АргументыКоманднойСтроки); + +КонецФункции // РазобратьАргументыКоманднойСтроки + +Функция ПолучитьПарсерКоманднойСтроки() + + Парсер = Новый ПарсерАргументовКоманднойСтроки(); + МенеджерКомандПриложения.ЗарегистрироватьКоманды(Парсер); + Возврат Парсер; + +КонецФункции // ПолучитьПарсерКоманднойСтроки + +/////////////////////////////////////////////////////////////////// + +Инициализация(); + +Попытка + + КодВозврата = ВыполнениеКоманды(); + ЗавершитьРаботу(КодВозврата); + +Исключение + + Лог.КритичнаяОшибка(ОписаниеОшибки()); + ЗавершитьРаботу(МенеджерКомандПриложения.РезультатыКоманд().ОшибкаВремениВыполнения); + +КонецПопытки; diff --git a/src/Классы/КомандаVersion.os b/src/Классы/КомандаVersion.os new file mode 100644 index 0000000..aa931fa --- /dev/null +++ b/src/Классы/КомандаVersion.os @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////// +// +// Служебный модуль с реализацией работы команды version +// +// Структура модуля реализована в соответствии с рекомендациями +// oscript-app-template (C) EvilBeaver +// +/////////////////////////////////////////////////////////////////// + +Процедура ЗарегистрироватьКоманду(Знач ИмяКоманды, Знач Парсер) Экспорт + + ОписаниеКоманды = Парсер.ОписаниеКоманды(ИмяКоманды, "Выводит версию приложения"); + Парсер.ДобавитьКоманду(ОписаниеКоманды); + +КонецПроцедуры // ЗарегистрироватьКоманду + +// Выполняет логику команды +// +// Параметры: +// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений +// ДополнительныеПараметры - Соответствие - дополнительные параметры (необязательно) +// +Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач ДополнительныеПараметры) Экспорт + + Сообщить(ПараметрыСистемы.ВерсияПродукта()); + Возврат МенеджерКомандПриложения.РезультатыКоманд().Успех; + +КонецФункции // ВыполнитьКоманду diff --git a/src/Классы/КомандаЗакрытьИшузы.os b/src/Классы/КомандаЗакрытьИшузы.os new file mode 100644 index 0000000..a53f8db --- /dev/null +++ b/src/Классы/КомандаЗакрытьИшузы.os @@ -0,0 +1,226 @@ +Перем Лог; + +Перем Токен; +Перем АдресСервера; +Перем РодительскийПроект; +Перем ДочерниеПроекты; +Перем ИсключаемыеПроекты; +Перем Статусы; +Перем ИзEDTВКонфигуратор; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Прикладной интерфейс +/////////////////////////////////////////////////////////////////////////////////////////////////// + +Процедура ЗарегистрироватьКоманду(Знач ИмяКоманды, Знач Парсер) Экспорт + + ОписаниеКоманды = Парсер.ОписаниеКоманды(ИмяКоманды, "Выполняет закрытие замечаний (как не требующих исправление) из родительского проекта в дочерних"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--token", "Токен для авторизации на сервере SonarQube"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--server", "Адрес сервера SonarQube (например http://my.sonar.server:9000)"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--parent-project", "Ключ родительского проекта (например bsp:master)"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--child-projects", "Ключи дочерних проектов, строкой через запятую (например hrm:develop,buh:master). + | Для того, чтобы указать все проекты, необходимо передать #all"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--exclude-projects", "Ключи дочерних проектов, которые необходимо исключить из обработки"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--statuses", "Отбор замечаний родительского проекта только соответствующих статусов. + | Необходимые статусы необходимо передавать строкой через запятую. + | Возможные значения: + | OPEN - открытые + | CONFIRMED - подтвержденные: + | REOPENED - переоткрытые + | RESOLVED - решенные + | CLOSED - закрытые + | + | По умолчанию выбираются только RESOLVED и CLOSED"); + Парсер.ДобавитьПараметрФлагКоманды(ОписаниеКоманды, "--edt2cfg", "Необходимо использовать тогда, когда родительский проект в формате EDT, а дочерний в формате конфигуратора"); + Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "--cfg-file", "Путь к конфигурационному файлу в формате json (utf-8), свойства объекта соответствуют ключам запуска. + | Пример конфигурационного файла находится в каталоге examples"); + + Парсер.ДобавитьКоманду(ОписаниеКоманды); + +КонецПроцедуры + +// Выполняет логику команды +// +// Параметры: +// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений +// ДополнительныеПараметры - Соответствие - (необязательно) дополнительные параметры +// +Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач ДополнительныеПараметры = Неопределено) Экспорт + + Лог = ДополнительныеПараметры.Лог; + ОшибокНет = ПрочитатьПараметрыЗапуска(ПараметрыКоманды); + Если НЕ ОшибокНет Тогда + Возврат СообщитьОбОшибке("Ошибка запуска"); + КонецЕсли; + + Лог.Информация("Получение информации о проектах"); + ПроектыSQ = Сонар.ПолучитьПроекты(АдресСервера, Токен); + Лог.Информация("Получение информации о родительском проекте"); + ОписаниеРодительскогоПроекта = ПроектыSQ.Получить(РодительскийПроект); + Если ОписаниеРодительскогоПроекта = Неопределено Тогда + Возврат СообщитьОбОшибке(СтрШаблон("Родительский проект `%1` в списке проектов не обнаружен", РодительскийПроект)); + КонецЕсли; + + Лог.Информация("Получение закрываемых замечаний из родительского проекта"); + ЗамечанияРодительскогоПроекта = Сонар.ПолучитьЗамечанияПроекта( + АдресСервера, Токен, + ОписаниеРодительскогоПроекта, + Статусы, + ИзEDTВКонфигуратор); + + Если НЕ ЗамечанияРодительскогоПроекта.Количество() Тогда + + Лог.Информация("Закрываемых замечаний в родительском проекте нет"); + Возврат МенеджерКомандПриложения.РезультатыКоманд().Успех; + + КонецЕсли; + + Если ДочерниеПроекты.Найти("#all") <> Неопределено Тогда + ДочерниеПроекты.Очистить(); + Для Каждого ОписаниеПроекта Из ПроектыSQ Цикл + Если ОписаниеПроекта.Ключ <> РодительскийПроект Тогда + ДочерниеПроекты.Добавить(ОписаниеПроекта.Ключ); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Для Каждого ИсключаемыйПроект Из ИсключаемыеПроекты Цикл + Позиция = ДочерниеПроекты.Найти(СокрЛП(ИсключаемыйПроект)); + Если Позиция <> Неопределено Тогда + ДочерниеПроекты.Удалить(Позиция); + КонецЕсли; + КонецЦикла; + + Лог.Информация("Закрытие замечаний в дочерних проектах"); + Для Каждого ДочернийПроект Из ДочерниеПроекты Цикл + Лог.Информация("Закрытие замечаний в проекте `%1`", ДочернийПроект); + ОписаниеПроекта = ПроектыSQ.Получить(СокрЛП(ДочернийПроект)); + Если ОписаниеПроекта = Неопределено Тогда + Лог.Ошибка("Проект `%1` не обнаружен", ДочернийПроект); + Продолжить; + КонецЕсли; + + ЗакрываемыеЗамечания = Сонар.ПолучитьЗакрываемыеЗамечания(АдресСервера, Токен, ОписаниеПроекта, ЗамечанияРодительскогоПроекта); + Если ЗакрываемыеЗамечания.Количество() Тогда + Лог.Информация("Для проекта `%1` будет закрыто замечаний: `%2` ", ДочернийПроект, ЗакрываемыеЗамечания.Количество()); + Сонар.ЗакрытьЗамечания(АдресСервера, Токен, ЗакрываемыеЗамечания, "Привнесено '" + РодительскийПроект + "'"); + КонецЕсли; + КонецЦикла; + + Возврат МенеджерКомандПриложения.РезультатыКоманд().Успех; + +КонецФункции + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +Функция ПрочитатьПараметрыЗапуска(ПараметрыКоманды) + + ОшибокНет = Истина; + + Токен = ПараметрыКоманды["--token"]; + АдресСервера = ПараметрыКоманды["--server"]; + РодительскийПроект = ПараметрыКоманды["--parent-project"]; + ДочерниеПроектыСтрокой = ПараметрыКоманды["--child-projects"]; + ИсключаемыеПроектыСтрокой = ПараметрыКоманды["--exclude-projects"]; + СтатусыСтрокой = ПараметрыКоманды["--statuses"]; + ИзEDTВКонфигуратор = ПараметрыКоманды["--edt2cfg"]; + + ПутьККонфигурационномуФайлу = ПараметрыКоманды["--cfg-file"]; + Если ПутьККонфигурационномуФайлу <> Неопределено Тогда + + Файл = Новый Файл(ПутьККонфигурационномуФайлу); + Если Файл.Существует() Тогда + ТекстовыйДокумент = Новый ТекстовыйДокумент(); + ТекстовыйДокумент.Прочитать(ПутьККонфигурационномуФайлу); + Лог.Отладка("Содержимое конфигурационного файла: %1%2", Символы.ПС, ТекстовыйДокумент.ПолучитьТекст()); + JSON = Новый ЧтениеJSON(); + JSON.УстановитьСтроку(ТекстовыйДокумент.ПолучитьТекст()); + ПараметрыИзФайла = ПрочитатьJSON(JSON, Истина); + Если Токен = Неопределено Тогда + Токен = ПараметрыИзФайла.Получить("--token"); + КонецЕсли; + Если АдресСервера = Неопределено Тогда + АдресСервера = ПараметрыИзФайла.Получить("--server"); + КонецЕсли; + Если РодительскийПроект = Неопределено Тогда + РодительскийПроект = ПараметрыИзФайла.Получить("--parent-project"); + КонецЕсли; + Если ДочерниеПроектыСтрокой = Неопределено Тогда + ДочерниеПроектыСтрокой = ПараметрыИзФайла.Получить("--child-projects"); + КонецЕсли; + Если ИсключаемыеПроектыСтрокой = Неопределено Тогда + ИсключаемыеПроектыСтрокой = ПараметрыИзФайла.Получить("--exclude-projects"); + КонецЕсли; + Если СтатусыСтрокой = Неопределено Тогда + СтатусыСтрокой = ПараметрыИзФайла.Получить("--statuses"); + КонецЕсли; + Если ИзEDTВКонфигуратор = Ложь И ПараметрыИзФайла.Получить("--edt2cfg") <> Неопределено Тогда + ИзEDTВКонфигуратор = ПараметрыИзФайла.Получить("--edt2cfg"); + КонецЕсли; + Иначе + Лог.Ошибка("Конфигурационный файл по пути `%1` не обнаружен", ОбернутьЗначениеДляПечати(ПутьККонфигурационномуФайлу)); + ОшибокНет = Ложь; + КонецЕсли; + + КонецЕсли; + + Лог.Отладка("Прочитанные параметры:"); + Лог.Отладка(" Токен = `%1`", ОбернутьЗначениеДляПечати(Токен)); + Лог.Отладка(" Адрес сервера = `%1`", ОбернутьЗначениеДляПечати(АдресСервера)); + Лог.Отладка(" Ключ родительского проекта = `%1`", ОбернутьЗначениеДляПечати(РодительскийПроект)); + Лог.Отладка(" Ключ дочерних проектов (строкой) = `%1`", ОбернутьЗначениеДляПечати(ДочерниеПроектыСтрокой)); + Лог.Отладка(" Ключ исключаемых проектов (строкой) = `%1`", ОбернутьЗначениеДляПечати(ИсключаемыеПроектыСтрокой)); + Лог.Отладка(" Статусы строкой = `%1`", ОбернутьЗначениеДляПечати(СтатусыСтрокой)); + Лог.Отладка(" Нужно переводить из EDT = `%1`", ОбернутьЗначениеДляПечати(ИзEDTВКонфигуратор)); + + Если Не ЗначениеЗаполнено(Токен) Тогда + Лог.Ошибка("Не указан токен для авторизации"); + ОшибокНет = Ложь; + КонецЕсли; + + Если Не ЗначениеЗаполнено(АдресСервера) Тогда + Лог.Ошибка("Не указан адрес сервера SonarQube"); + ОшибокНет = Ложь; + КонецЕсли; + + Если Не ЗначениеЗаполнено(РодительскийПроект) Тогда + Лог.Ошибка("Не указан ключ родительского проекта"); + ОшибокНет = Ложь; + КонецЕсли; + + Если Не ЗначениеЗаполнено(ДочерниеПроектыСтрокой) Тогда + Лог.Ошибка("Не указаны ключ дочерних проектов"); + ОшибокНет = Ложь; + Иначе + ДочерниеПроекты = СтрРазделить(ДочерниеПроектыСтрокой, ",", Ложь); + КонецЕсли; + + ИсключаемыеПроекты = Новый Массив(); + Если ЗначениеЗаполнено(ИсключаемыеПроектыСтрокой) Тогда + ИсключаемыеПроекты = СтрРазделить(ИсключаемыеПроектыСтрокой, ",", Ложь); + КонецЕсли; + ИсключаемыеПроекты.Добавить(СокрЛП(РодительскийПроект)); + + Если Не ЗначениеЗаполнено(СтатусыСтрокой) Тогда + Статусы = СтрРазделить("RESOLVED,CLOSED", ",", Ложь); + Иначе + Статусы = СтрРазделить(СтатусыСтрокой, ",", Ложь); + КонецЕсли; + + Возврат ОшибокНет; + +КонецФункции + +Функция ОбернутьЗначениеДляПечати(Знач Значение) + Если ЗначениеЗаполнено(Значение) Тогда + Возврат Строка(Значение); + КонецЕсли; + Возврат "<Незаполнено>"; +КонецФункции + +Функция СообщитьОбОшибке(ТекстОшибки) + + Лог.Ошибка(ТекстОшибки); + Возврат МенеджерКомандПриложения.РезультатыКоманд().ОшибкаВремениВыполнения; + +КонецФункции diff --git a/src/Классы/КомандаСправкаПоПараметрам.os b/src/Классы/КомандаСправкаПоПараметрам.os new file mode 100644 index 0000000..43931d9 --- /dev/null +++ b/src/Классы/КомандаСправкаПоПараметрам.os @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////// +// +// Служебный модуль с набором методов работы с командами приложения +// +// Структура модуля реализована в соответствии с рекомендациями +// oscript-app-template (C) EvilBeaver +// +/////////////////////////////////////////////////////////////////// + +Процедура ЗарегистрироватьКоманду(Знач ИмяКоманды, Знач Парсер) Экспорт + + ОписаниеКоманды = Парсер.ОписаниеКоманды(ИмяКоманды, "Выводит справку по параметрам"); + Парсер.ДобавитьПозиционныйПараметрКоманды(ОписаниеКоманды, "Команда", "Имя команды, для которой выводится справка"); + Парсер.ДобавитьКоманду(ОписаниеКоманды); + +КонецПроцедуры // ЗарегистрироватьКоманду + +// Выполняет логику команды +// +// Параметры: +// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений +// ДополнительныеПараметры - Соответствие - дополнительные параметры (необязательно) +// +Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач Неиспользуется = Неопределено) Экспорт + + Парсер = Новый ПарсерАргументовКоманднойСтроки; + + МенеджерКомандПриложения.ЗарегистрироватьКоманды(Парсер); + + Если ПараметрыКоманды["Команда"] = Неопределено Тогда + + ПоказатьВозможныеКоманды(Парсер); + + Иначе + + ПоказатьСправкуПоКоманде(Парсер, ПараметрыКоманды["Команда"]); + + КонецЕсли; + + Возврат МенеджерКомандПриложения.РезультатыКоманд().Успех; + +КонецФункции // ВыполнитьКоманду + +Процедура ПоказатьВозможныеКоманды(Знач Парсер) + + Парсер.ВывестиСправкуПоКомандам(); + +КонецПроцедуры // ПоказатьВозможныеКоманды + +Процедура ПоказатьСправкуПоКоманде(Знач Парсер, Знач ИмяКоманды) + + Парсер.ВывестиСправкуПоКоманде(ИмяКоманды); + +КонецПроцедуры // ПоказатьСправкуПоКоманде diff --git a/src/Модули/МенеджерКомандПриложения.os b/src/Модули/МенеджерКомандПриложения.os new file mode 100644 index 0000000..2024859 --- /dev/null +++ b/src/Модули/МенеджерКомандПриложения.os @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////// +// +// Служебный модуль с набором методов работы с командами приложения +// +// Структура модуля реализована в соответствии с рекомендациями +// oscript-app-template (C) EvilBeaver +// +/////////////////////////////////////////////////////////////////// + +#Использовать logos + +/////////////////////////////////////////////////////////////////// + +Перем ИсполнителиКоманд; +Перем РегистраторКоманд; +Перем ДополнительныеПараметры; + +/////////////////////////////////////////////////////////////////// + +Процедура ЗарегистрироватьКоманды(Знач Парсер) Экспорт + + КомандыИРеализация = Новый Соответствие; + РегистраторКоманд.ПриРегистрацииКомандПриложения(КомандыИРеализация); + + Для Каждого КлючИЗначение Из КомандыИРеализация Цикл + + ДобавитьКоманду(КлючИЗначение.Ключ, КлючИЗначение.Значение, Парсер); + + КонецЦикла; + +КонецПроцедуры // ЗарегистрироватьКоманды + +Процедура РегистраторКоманд(Знач ОбъектРегистратор) Экспорт + + ИсполнителиКоманд = Новый Соответствие; + РегистраторКоманд = ОбъектРегистратор; + ДополнительныеПараметры = Новый Структура; + + ДополнительныеПараметры.Вставить("Лог", Логирование.ПолучитьЛог(ПараметрыСистемы.ИмяЛогаСистемы())); + +КонецПроцедуры // РегистраторКоманд + +Функция ПолучитьКоманду(Знач ИмяКоманды) Экспорт + + КлассРеализации = ИсполнителиКоманд[ИмяКоманды]; + Если КлассРеализации = Неопределено Тогда + + ВызватьИсключение "Неверная операция. Команда '" + ИмяКоманды + "' не предусмотрена."; + + КонецЕсли; + + Возврат КлассРеализации; + +КонецФункции // ПолучитьКоманду + +Функция ВыполнитьКоманду(Знач ИмяКоманды, Знач ПараметрыКоманды) Экспорт + + Команда = ПолучитьКоманду(ИмяКоманды); + КодВозврата = Команда.ВыполнитьКоманду(ПараметрыКоманды, ДополнительныеПараметры); + + Возврат КодВозврата; + +КонецФункции // ВыполнитьКоманду + +Процедура ПоказатьСправкуПоКомандам(ИмяКоманды = Неопределено) Экспорт + + ПараметрыКоманды = Новый Соответствие; + Если ИмяКоманды <> Неопределено Тогда + + ПараметрыКоманды.Вставить("Команда", ИмяКоманды); + + КонецЕсли; + + ВыполнитьКоманду(ПараметрыСистемы.ВозможныеКоманды().Помощь, ПараметрыКоманды); + +КонецПроцедуры // ПоказатьСправкуПоКомандам + +Процедура ДобавитьКоманду(Знач ИмяКоманды, Знач КлассРеализации, Знач Парсер) + + Попытка + РеализацияКоманды = Новый(КлассРеализации); + РеализацияКоманды.ЗарегистрироватьКоманду(ИмяКоманды, Парсер); + ИсполнителиКоманд.Вставить(ИмяКоманды, РеализацияКоманды); + Исключение + ДополнительныеПараметры.Лог.Ошибка("Не удалось выполнить команду %1 для класса %2", ИмяКоманды, КлассРеализации); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +/////////////////////////////////////////////////////////////////// + +Функция РезультатыКоманд() Экспорт + + РезультатыКоманд = Новый Структура; + РезультатыКоманд.Вставить("Успех", 0); + РезультатыКоманд.Вставить("НеверныеПараметры", 5); + РезультатыКоманд.Вставить("ОшибкаВремениВыполнения", 1); + + Возврат РезультатыКоманд; + +КонецФункции // РезультатыКоманд + +Функция КодВозвратаКоманды(Знач Команда) Экспорт + + Возврат Число(Команда); + +КонецФункции // КодВозвратаКоманды diff --git a/src/Модули/ПараметрыСистемы.os b/src/Модули/ПараметрыСистемы.os new file mode 100644 index 0000000..8717ab5 --- /dev/null +++ b/src/Модули/ПараметрыСистемы.os @@ -0,0 +1,85 @@ +/////////////////////////////////////////////////////////////////// +// +// Служебный модуль с набором служебных параметров приложения +// +// Структура модуля реализована в соответствии с рекомендациями +// oscript-app-template (C) EvilBeaver +// +/////////////////////////////////////////////////////////////////// + +Перем ВозможныеКомандыПриложения; + +// Возвращает идентификатор лога приложения +// +// Возвращаемое значение: +// Строка - Значение идентификатора лога приложения +// +Функция ИмяЛогаСистемы() Экспорт + + Возврат "oscript.app." + ИмяПродукта(); + +КонецФункции // ИмяЛогаСистемы + +// Возвращает текущую версию продукта +// +// Возвращаемое значение: +// Строка - Значение текущей версии продукта +// +Функция ВерсияПродукта() Экспорт + + Версия = "1.0.1"; + Возврат Версия; + +КонецФункции // ВерсияПродукта() + +// Возвращает имя продукта +// +// Возвращаемое значение: +// Строка - имя продукта +// +Функция ИмяПродукта() Экспорт + Возврат "sonar-helper"; +КонецФункции + +Функция ВозможныеКоманды() Экспорт + + Если ВозможныеКомандыПриложения = Неопределено Тогда + + ВозможныеКомандыПриложения = Новый Структура; + ВозможныеКомандыПриложения.Вставить("Помощь", "help"); + ВозможныеКомандыПриложения.Вставить("ПоказатьВерсию", "version"); + ВозможныеКомандыПриложения.Вставить("ЗакрытьИшузы", "issue-resolver"); + + ВозможныеКомандыПриложения = Новый ФиксированнаяСтруктура(ВозможныеКомандыПриложения); + + КонецЕсли; + + Возврат ВозможныеКомандыПриложения; + +КонецФункции + +Процедура ПриРегистрацииКомандПриложения(Знач КлассыРеализацииКоманд) Экспорт + + КлассыРеализацииКоманд[ВозможныеКоманды().Помощь] = "КомандаСправкаПоПараметрам"; + КлассыРеализацииКоманд[ИмяКомандыВерсия()] = "КомандаVersion"; + КлассыРеализацииКоманд[ВозможныеКоманды().ЗакрытьИшузы] = "КомандаЗакрытьИшузы"; + //... + //КлассыРеализацииКоманд["<имя команды>"] = "<КлассРеализации>"; + +КонецПроцедуры // ПриРегистрацииКомандПриложения + +// Одна из команд может вызываться неявно, без указания команды. +// Иными словами, здесь указывается какой обработчик надо вызывать, если приложение запущено без какой-либо команды +// myapp /home/user/somefile.txt будет аналогично myapp default-action /home/user/somefile.txt +Функция ИмяКомандыПоУмолчанию() Экспорт + Возврат ВозможныеКоманды().Помощь; +КонецФункции + +// Возвращает имя команды версия (ключ командной строки) +// +// Возвращаемое значение: +// Строка - имя команды +// +Функция ИмяКомандыВерсия() Экспорт + Возврат ВозможныеКоманды().ПоказатьВерсию; +КонецФункции diff --git a/src/Модули/Сонар.os b/src/Модули/Сонар.os new file mode 100644 index 0000000..e11e549 --- /dev/null +++ b/src/Модули/Сонар.os @@ -0,0 +1,271 @@ +/////////////////////////////////////////////////////////////////// +// +// Модуль с набором методов работы с SonarQube +// Используются методы rest-api sonarqube +// (C) TheShadowCo +// +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +// Программный интерфейс +/////////////////////////////////////////////////////////////////// + +// ПолучитьПроекты +// Возвращает набор проектов +// Параметры: +// АдресСервера - Строка - Адрес (хост) сервера SonarQube +// Токен - Строка - Токен пользователя, от имени которого выполняются запросы к API +// +// Возвращаемое значение: +// Соответствие - Коллекция проектов +// * Ключ - Строка - Код (Ключ) проекта +// * Значение - Структура - Описание проекта +// ** Идентификатор - Строка - Идентификатор проекта +// ** Код - Строка - Код (Ключ) проекта +// +Функция ПолучитьПроекты(АдресСервера, Токен) Экспорт + + URLШаблон = "components/search?qualifiers=TRK&ps=500&p=%1"; + НомерСтраницы = 1; + Проекты = Новый Соответствие(); + + Пока Истина Цикл + + URL = СтрШаблон(URLШаблон, Формат(НомерСтраницы, "ЧГ=")); + Ответ = ВыполнитьЗапрос(АдресСервера, Токен, URL, "GET"); + + Для Каждого ОписаниеПроекта Из Ответ.components Цикл + + НовыйПроект = Новый Структура(); + НовыйПроект.Вставить("Идентификатор", ОписаниеПроекта.id); + НовыйПроект.Вставить("Код", ОписаниеПроекта.key); + Проекты.Вставить(НовыйПроект.Код, НовыйПроект); + + КонецЦикла; + + Если БольшеНетДанных(Ответ) Тогда + Прервать; + КонецЕсли; + + НомерСтраницы = НомерСтраницы + 1; + + КонецЦикла; + + Возврат Проекты; + +КонецФункции + +// ПолучитьЗамечанияПроекта +// Возвращает набор замечаний проекта по установленным отборам +// Параметры: +// АдресСервера - Строка - Адрес (хост) сервера SonarQube +// Токен - Строка - Токен пользователя, от имени которого выполняются запросы к API +// ОписаниеПроекта - Структура - Описание проекта SonarQube +// * Идентификатор - Строка - Идентификатор проекта +// * Код - Строка - Код (Ключ) проекта +// Статусы - Массив - Массив строковых идентификаторов статусов замечаний +// ИзEDTВКонфигуратор - Булево - Признак необходимости преобразования замечаний между родительским проектом и дочерними +// +// Возвращаемое значение: +// Соответствие - Коллекция замечаний +// * Ключ - Строка - Относительный путь к файлу, в котором зафиксировано замечание +// * Значение - Структура - Описание проекта +// ** ПутьКФайлу - Строка - Относительный путь к файлу, в котором зафиксировано замечание +// ** Ошибки - Соответствие - Набор зарегистрированных замечаний (ошибок) +// *** Ключ - Строка - Хэш замечания +// *** Значение - Структура - Описание замечания +// **** ПутьКФайлу - Строка - Относительный путь к файлу, в котором зафиксировано замечание +// **** Код - Строка - Ключ замечания +// **** Хэш - Строка - Хэш замечания +// +Функция ПолучитьЗамечанияПроекта(АдресСервера, Токен, ОписаниеПроекта, Статусы, ИзEDTВКонфигуратор) Экспорт + + URLШаблон = "issues/search?ps=500&statuses=%1&projectUuids=%2&p="; + Замечания = Новый Соответствие(); + + Для Каждого Статус Из Статусы Цикл + + НомерСтраницы = 1; + Пока Истина Цикл + URL = СтрШаблон(URLШаблон, ВРег(СокрЛП(Статус)), ОписаниеПроекта.Идентификатор); + Ответ = ВыполнитьЗапрос(АдресСервера, Токен, URL + Формат(НомерСтраницы, "ЧГ="), "GET"); + + Для Каждого ОписаниеОшибки Из Ответ.issues Цикл + + ПутьКФайлу = СтрЗаменить(ОписаниеОшибки.component, ОписаниеПроекта.Код + ":", ""); + Если ИзEDTВКонфигуратор Тогда + ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "configuration/src/", "src/configuration/"); + ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "/ManagerModule.bsl", "/Ext/ManagerModule.bsl"); + ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "/ObjectModule.bsl", "/Ext/ObjectModule.bsl"); + ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "/CommandModule.bsl", "/Ext/CommandModule.bsl"); + ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "/ValueManagerModule.bsl", "/Ext/ValueManagerModule.bsl"); + ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "/configuration/Configuration", "/configuration/Ext"); + Если СтрНайти(ПутьКФайлу, "Forms") Тогда + ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "/Module.bsl", "/Ext/Form/Module.bsl"); + Иначе + ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "/Module.bsl", "/Ext/Module.bsl"); + КонецЕсли; + КонецЕсли; + + НовоеОписаниеОшибки = Новый Структура(); + НовоеОписаниеОшибки.Вставить("ПутьКФайлу", ПутьКФайлу); + НовоеОписаниеОшибки.Вставить("Код", ОписаниеОшибки.key); + Хэш = ПолучитьХэшЗамечания(ОписаниеОшибки, ПутьКФайлу); + НовоеОписаниеОшибки.Вставить("Хэш", Хэш); + + ТекущийМодуль = Замечания.Получить(ПутьКФайлу); + Если ТекущийМодуль = Неопределено Тогда + ТекущийМодуль = Новый Структура("ПутьКФайлу, Ошибки", ПутьКФайлу, Новый Соответствие()); + КонецЕсли; + ТекущийМодуль.Ошибки.Вставить(Хэш, НовоеОписаниеОшибки); + + Замечания.Вставить(ПутьКФайлу, ТекущийМодуль); + + КонецЦикла; + + Если БольшеНетДанных(Ответ) Тогда + Прервать; + КонецЕсли; + + НомерСтраницы = НомерСтраницы + 1; + + КонецЦикла; + + КонецЦикла; + + Возврат Замечания; + +КонецФункции + +// ПолучитьЗакрываемыеЗамечания +// Возвращает набор открытых замечаний проекта, которые необходимо закрыть +// Параметры: +// АдресСервера - Строка - Адрес (хост) сервера SonarQube +// Токен - Строка - Токен пользователя, от имени которого выполняются запросы к API +// ОписаниеПроекта - Структура - Описание проекта SonarQube +// * Идентификатор - Строка - Идентификатор проекта +// * Код - Строка - Код (Ключ) проекта +// ЗамечанияРодительскогоПроекта - Соответствие - Замечания для закрытия из родительского проекта. См. ПолучитьЗамечанияПроекта +// +// Возвращаемое значение: +// Соответствие - Коллекция замечаний +// * Ключ - Строка - Хэш замечания +// * Значение - Структура - Описание замечания +// ** ПутьКФайлу - Строка - Относительный путь к файлу, в котором зафиксировано замечание +// ** Код - Строка - Ключ замечания +// ** Хэш - Строка - Хэш замечания +// +Функция ПолучитьЗакрываемыеЗамечания(АдресСервера, Токен, ОписаниеПроекта, ЗамечанияРодительскогоПроекта) Экспорт + + URLШаблон = "issues/search?ps=500&statuses=OPEN,CONFIRMED,REOPENED&projectUuids=%1&componentKeys=%2&p="; + Замечания = Новый Соответствие(); + + Для Каждого МодульСЗмечаниями Из ЗамечанияРодительскогоПроекта Цикл + + URL = СтрШаблон(URLШаблон, ОписаниеПроекта.Идентификатор, ОписаниеПроекта.Код + ":" + МодульСЗмечаниями.Ключ); + НомерСтраницы = 1; + Пока Истина Цикл + + Ответ = ВыполнитьЗапрос(АдресСервера, Токен, URL + Формат(НомерСтраницы, "ЧГ="), "GET"); + Для Каждого ОписаниеОшибки Из Ответ.issues Цикл + + ПутьКФайлу = СтрЗаменить(ОписаниеОшибки.component, ОписаниеПроекта.Код + ":", ""); + Хэш = ПолучитьХэшЗамечания(ОписаниеОшибки, ПутьКФайлу); + + Если МодульСЗмечаниями.Значение.Ошибки.Получить(Хэш) = Неопределено Тогда + Продолжить; + КонецЕсли; + + НовоеОписаниеОшибки = Новый Структура(); + НовоеОписаниеОшибки.Вставить("ПутьКФайлу", ПутьКФайлу); + НовоеОписаниеОшибки.Вставить("Код", ОписаниеОшибки.key); + НовоеОписаниеОшибки.Вставить("Хэш", Хэш); + Замечания.Вставить(Хэш, НовоеОписаниеОшибки); + + КонецЦикла; + + Если БольшеНетДанных(Ответ) Тогда + Прервать; + КонецЕсли; + + НомерСтраницы = НомерСтраницы + 1; + + КонецЦикла; + + КонецЦикла; + + Возврат Замечания; + +КонецФункции + +// ЗакрытьЗамечания +// Выполняет закрытие замечаний: устанавливает признак "WONTFIX" со ссылкой на родительский проект +// Параметры: +// АдресСервера - Строка - Адрес (хост) сервера SonarQube +// Токен - Строка - Токен пользователя, от имени которого выполняются запросы к API +// ЗакрываемыеЗамечания - Соответствие - Замечания, которые привнесены из родительского проекта и требуют закрытия. См. ПолучитьЗакрываемыеЗамечания +// Комментарий - Строка - Текстовое сообщение, которое будет добавлено как коментарий к закрываемому замечанию +// +Процедура ЗакрытьЗамечания(АдресСервера, Токен, ЗакрываемыеЗамечания, Комментарий) Экспорт + + URL = СтрШаблон("issues/bulk_change?do_transition=wontfix&comment=%1&issues=", Комментарий); + ЗамечанияДляОбработки = Новый Массив(); + Для Каждого Замечание Из ЗакрываемыеЗамечания Цикл + + Если ЗамечанияДляОбработки.Количество() = 100 Тогда + ВыполнитьЗапрос(АдресСервера, Токен, URL + СтрСоединить(ЗамечанияДляОбработки, ","), "POST"); + ЗамечанияДляОбработки.Очистить(); + КонецЕсли; + + ЗамечанияДляОбработки.Добавить(Замечание.Значение.Идентификатор); + + КонецЦикла; + + Если ЗамечанияДляОбработки.Количество() Тогда + ВыполнитьЗапрос(АдресСервера, Токен, URL + СтрСоединить(ЗамечанияДляОбработки, ","), "POST"); + КонецЕсли; + +КонецПроцедуры + +/////////////////////////////////////////////////////////////////// +// Слубные процедуры и функции +/////////////////////////////////////////////////////////////////// + +Функция БольшеНетДанных(ОтветСервера) + + Возврат ОтветСервера.paging.pageSize * ОтветСервера.paging.pageIndex >= ОтветСервера.paging.total; + +КонецФункции + +Функция ПолучитьХэшЗамечания(ОписаниеОшибки, ПутьКФайлу) + Возврат ПутьКФайлу + ОписаниеОшибки.rule + + ?(ОписаниеОшибки.Свойство("textRange"), + "" + ОписаниеОшибки.textRange.startLine + ОписаниеОшибки.textRange.endLine + + ОписаниеОшибки.textRange.startOffset + ОписаниеОшибки.textRange.endOffset, + ""); +КонецФункции + +Функция ВыполнитьЗапрос(АдресСервера, Токен, URL, Операция) + + HTTPЗапрос = Новый HTTPЗапрос; + HTTPЗапрос.АдресРесурса = "/api/" + URL; + HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json"); + + HTTP = Новый HTTPСоединение(АдресСервера, , Токен); + Если Операция = "GET" Тогда + ОтветHTTP = HTTP.Получить(HTTPЗапрос); + Иначе + ОтветHTTP = HTTP.ОтправитьДляОбработки(HTTPЗапрос); + КонецЕсли; + + Если ОтветHTTP.КодСостояния = 200 Тогда + json = Новый ЧтениеJSON(); + json.УстановитьСтроку(ОтветHTTP.ПолучитьТелоКакСтроку()); + Возврат ПрочитатьJson(json); + КонецЕсли; + + ВызватьИсключение + "Код ответа: " + ОтветHTTP.КодСостояния + Символы.ПС + + "Ответ: " + ОтветHTTP.ПолучитьТелоКакСтроку(); + +КонецФункции