1
0
mirror of https://github.com/bia-technologies/precommit4onec.git synced 2026-04-26 20:05:36 +02:00

Merge pull request #9 from bia-technologies/feature/gh7

Feature/gh7
This commit is contained in:
Maximov Valery
2020-10-05 08:22:38 +03:00
committed by GitHub
8 changed files with 494 additions and 45 deletions
+12 -7
View File
@@ -75,16 +75,20 @@ precommit4onec может читать настройки своей работ
```JSON
{
"GLOBAL": { // необязательная секция
"ВерсияПлатформы": "8.3.10.2309", // используемая версия платформы например для разбора на исходники
"version": "2.0" // версия конфигурационного файла (необязательно)
},
"Precommt4onecСценарии": {
"ИспользоватьСценарииРепозитория": false, // Признак, выполнения проверок из репозитория
"КаталогЛокальныхСценариев": "", // Относительный путь к каталогу локальных проверок
"ГлобальныеСценарии": [...], // Список проверок, которые будут выполнятся
"ОтключенныеСценарии": [...], // Список проверок, которые не будут выполнятся (имеет больший приоритет относительно ГлобальныеСценарии)
"НастройкиСценариев": { // Настройки выполняемых проверок
"ИспользоватьСценарииРепозитория": false, // Признак, выполнения проверок из репозитория
"КаталогЛокальныхСценариев": "", // Относительный путь к каталогу локальных проверок
"ГлобальныеСценарии": [...], // Список проверок, которые будут выполнятся
"ОтключенныеСценарии": [...], // Список проверок, которые не будут выполнятся (имеет больший приоритет относительно ГлобальныеСценарии)
"НастройкиСценариев": { // Настройки выполняемых проверок
...
},
"Проекты":{ // Настройки проектов (подкаталогов репозитория). Настройки проектов полностью переопределяют настройки и имеют такую же структуру
"configuration\\": { // Имя проекта (подкаталога)
"Проекты":{ // Настройки проектов (подкаталогов репозитория). Настройки проектов полностью переопределяют настройки и имеют такую же структуру
"configuration\\": { // Имя проекта (подкаталога)
"ИспользоватьСценарииРепозитория": false,
"ГлобальныеСценарии": []
}
@@ -93,6 +97,7 @@ precommit4onec может читать настройки своей работ
}
```
## Расширение функциональности
Для создания нового сценария обработки файлов необходимо воспользоваться шаблоном, находящимся в каталоге `СценарииОбработки` скрипта.
+1
View File
@@ -12,6 +12,7 @@
.ЗависитОт("gitrunner", "1.6.0")
.ЗависитОт("v8runner", "1.3.0")
.ЗависитОт("v8unpack", "1.0.4")
.ЗависитОт("semver", "0.5.2")
.ВключитьФайл("src")
.ВключитьФайл("v8config.json")
.ВключитьФайл("LICENSE")
@@ -19,7 +19,8 @@
Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "КаталогРепозитория",
"Каталог анализируемого репозитория");
Парсер.ДобавитьИменованныйПараметрКоманды(Команда, "-source-dir",
"Каталог расположения исходных файлов относительно корня репозитория. По умолчанию <src>");
"Каталог расположения исходных файлов относительно корня репозитория.
| Если сценариев несколько, указываются в кавычках через , . По умолчанию <src>");
Парсер.ДобавитьИменованныйПараметрКоманды(Команда, "-rules",
"Перечень правил для применения. Если сценариев несколько, указываются в кавычках через ,");
Парсер.ДобавитьИменованныйПараметрКоманды(Команда, "-cfg-file",
@@ -58,29 +59,45 @@
Если Не ЗначениеЗаполнено(КаталогИсходныхФайлов) Тогда
КаталогИсходныхФайлов = "src";
Иначе
КаталогиИсходныхФайлов = СтрЗаменить(ПараметрыКоманды["-source-dir"], " ", "");
МассивКаталоговИсходныхФайлов = СтрРазделить(КаталогиИсходныхФайлов, ",", Ложь);
КонецЕсли;
ТекущийКаталогИсходныхФайлов = ОбъединитьПути(КаталогРепозитория, КаталогИсходныхФайлов);
ФайлТекущийКаталогИсходныхФайлов = Новый Файл(ТекущийКаталогИсходныхФайлов);
ТекущийКаталогИсходныхФайлов = ФайлТекущийКаталогИсходныхФайлов.ПолноеИмя;
Если НЕ ФайлТекущийКаталогИсходныхФайлов.Существует() Тогда
ОбрабатываемыеФайлы = Новый Массив();
Лог.Ошибка("Каталога <%1> не существует", ТекущийКаталогИсходныхФайлов);
Для Каждого КаталогИсходныхФайлов Из МассивКаталоговИсходныхФайлов Цикл
ТекущийКаталогИсходныхФайлов = ОбъединитьПути(КаталогРепозитория, КаталогИсходныхФайлов);
ФайлТекущийКаталогИсходныхФайлов = Новый Файл(ТекущийКаталогИсходныхФайлов);
ТекущийКаталогИсходныхФайлов = ФайлТекущийКаталогИсходныхФайлов.ПолноеИмя;
Если НЕ ФайлТекущийКаталогИсходныхФайлов.Существует() Тогда
Лог.Ошибка("Каталога <%1> не существует", ТекущийКаталогИсходныхФайлов);
КонецЕсли;
КонецЕсли;
КаталогРепозитория = ФайлКаталогРепозитория.ПолноеИмя;
ОбрабатываемыеФайлыКаталога = НайтиФайлы(ТекущийКаталогИсходныхФайлов, "*", Истина);
Для Каждого ОбрабатываемыйФайлКаталога Из ОбрабатываемыеФайлыКаталога Цикл
ОбрабатываемыеФайлы.Добавить(ОбрабатываемыйФайлКаталога);
КонецЦикла;
КонецЦикла;
КаталогРепозитория = ФайлКаталогРепозитория.ПолноеИмя;
ИменаЗагружаемыхСценариев = Неопределено;
Если ЗначениеЗаполнено(ПараметрыКоманды["-rules"]) Тогда
ПараметрИменаСценариев = СтрЗаменить(ПараметрыКоманды["-rules"], " ", "");
ИменаЗагружаемыхСценариев = СтрРазделить(ПараметрИменаСценариев, ",", Ложь);
КонецЕсли;
ОбрабатываемыеФайлы = НайтиФайлы(ТекущийКаталогИсходныхФайлов, "*", Истина);
Ит = 0;
УправлениеНастройками = МенеджерНастроек.НастройкиРепозитория(АдресПоискаКонфигурационногоФайла);
@@ -77,18 +77,22 @@
ТЧ.Колонки.Добавить("Значение");
ТЧ.Колонки.Добавить("Количество");
СтрокиФайла = Новый Соответствие;
Для Каждого ГруппаИндексов Из ГруппыИндексов Цикл
СтрокаТЧ = ТЧ.ДОбавить();
СтрокаТЧ.Значение = Число(ГруппаИндексов.Группы[1].Значение);
СтрокаТЧ.Количество = 1;
СтрокиФайла.Вставить(СтрокаТЧ.Значение, ГруппаИндексов.Группы[1].Индекс);
Значение = Число(ГруппаИндексов.Группы[1].Значение);
СтрокаТЧ = ТЧ.Найти(Значение, "Значение");
Если СтрокаТЧ = Неопределено Тогда
СтрокаТЧ = ТЧ.Добавить();
СтрокаТЧ.Значение = Значение;
СтрокаТЧ.Количество = 1;
Иначе
СтрокаТЧ.Количество = СтрокаТЧ.Количество + 1;
КонецЕсли;
КонецЦикла;
// ТЧ.Свернуть("Значение", "Количество"); баг в движке oscript > 1.0.21 TODO: Вернуть свернуть
ТЧ.Свернуть("Значение", "Количество");
Если ТЧ.Количество() = ГруппыИндексов.Количество() Тогда
Возврат Ложь;
КонецЕсли;
@@ -97,7 +101,7 @@
ПоследнийНомер = ТЧ[0].Значение;
ТЧ.Сортировать("Количество УБЫВ");
Для каждого СтрокаТЧ Из ТЧ Цикл
Если СтрокаТЧ.Количество = 1 Тогда
Прервать;
@@ -123,6 +127,6 @@
ФайловыеОперации.ЗаписатьТекстФайла(ИмяФайла, СодержимоеФайла);
Возврат ИСТИНА;
Возврат Истина;
КонецФункции
КонецФункции
@@ -0,0 +1,134 @@
///////////////////////////////////////////////////////////////////////////////
//
// Служебный модуль с реализацией сценариев обработки файлов <ИмяСценария>
//
///////////////////////////////////////////////////////////////////////////////
// ИмяСценария
// Возвращает имя сценария обработки файлов
//
// Возвращаемое значение:
// Строка - Имя текущего сценария обработки файлов
//
Функция ИмяСценария() Экспорт
Возврат "ОбработкаЮнитТестов";
КонецФункции // ИмяСценария()
// ОбработатьФайл
// Выполняет обработку файла
//
// Параметры:
// АнализируемыйФайл - Файл - Файл из журнала git для анализа
// КаталогИсходныхФайлов - Строка - Каталог расположения исходных файлов относительно каталог репозитория
// ДополнительныеПараметры - Структура - Набор дополнительных параметров, которые можно использовать
// * Лог - Объект - Текущий лог
// * ИзмененныеКаталоги - Массив - Каталоги, которые необходимо добавить в индекс
// * КаталогРепозитория - Строка - Адрес каталога репозитория
// * ФайлыДляПостОбработки - Массив - Файлы, изменившиеся / образовавшиеся в результате работы сценария
// и которые необходимо дообработать
// * ИзмененныеКаталоги - Массив - Каталоги / файлы которые необходимо добавить в индекс
//
// Возвращаемое значение:
// Булево - Признак выполненной обработки файла
//
Функция ОбработатьФайл(АнализируемыйФайл, КаталогИсходныхФайлов, ДополнительныеПараметры) Экспорт
Лог = ДополнительныеПараметры.Лог;
НастройкиСценария = ДополнительныеПараметры.Настройки.Получить(ИмяСценария());
// анализ файла без изменения его содержимого
Если АнализируемыйФайл.Существует() И ТипыФайлов.ЭтоФайлИсходников(АнализируемыйФайл)
И СтрНайти(АнализируемыйФайл.ПолноеИмя, "/tests/") Тогда
Лог.Информация("Обработка файла '%1' по сценарию '%2'", АнализируемыйФайл.ПолноеИмя, ИмяСценария());
Если ОбработкаФайла(АнализируемыйФайл) Тогда
ДополнительныеПараметры.ИзмененныеКаталоги.Добавить(АнализируемыйФайл.ПолноеИмя);
КонецЕсли;
Возврат Истина;
КонецЕсли;
Возврат Ложь;
КонецФункции // ОбработатьФайл()
Функция ОбработкаФайла(Файл)
РегулярноеВыражениеМетоды = Новый РегулярноеВыражение("\/\/\s*?\@unit-test\:.*?\nПроцедура\s+?(.+)\s*?\(.*\s*Экспорт");
РегулярноеВыражениеМетоды.ИгнорироватьРегистр = Истина;
РегулярноеВыражениеМетоды.Многострочный = Истина;
РегулярноеВыражениеAPI = Новый РегулярноеВыражение("(#Область ТестыAPI\s*?[.\w\W]+?#КонецОбласти\s*?$)");
РегулярноеВыражениеAPI.ИгнорироватьРегистр = Истина;
РегулярноеВыражениеAPI.Многострочный = Истина;
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.Прочитать(Файл.ПолноеИмя, КодировкаТекста.UTF8NoBOM);
Текст = ТекстовыйДокумент.ПолучитьТекст();
Если Не ЗначениеЗаполнено(Текст) Тогда
Возврат Ложь;
КонецЕсли;
Совпадения = РегулярноеВыражениеМетоды.НайтиСовпадения(Текст);
ТекстМетода = "";
Если Совпадения.Количество() Тогда
Для Каждого Совпадение Из Совпадения Цикл
ТекстМетода = ТекстМетода + Символы.ПС
+ " ИсполняемыеСценарии.Добавить(""" + Совпадение.Группы[1].Значение + """);";
КонецЦикла;
КонецЕсли;
Если Не ПустаяСтрока(ТекстМетода) Тогда
ТекстМетода = "#Область ТестыAPI
|
|// ИсполняемыеСценарии
|// Сервисный метод для получения списка тестовых методов
|// Параметры:
|// ДополнительныеПараметры - Структура - Дополнительные параметры, используемые при формировании списка тестов
|// Возвращаемое значение:
|// Массив - Имена методов тестов
|Функция ИсполняемыеСценарии(ДополнительныеПараметры = Неопределено) Экспорт
|
| ИсполняемыеСценарии = Новый Массив; " + ТекстМетода + "
|
| Возврат ИсполняемыеСценарии;
|
|КонецФункции
|
|#КонецОбласти";
Совпадения = РегулярноеВыражениеAPI.НайтиСовпадения(Текст);
НовыйТекстМодуля = Текст;
Если Совпадения.Количество() Тогда
НовыйТекстМодуля = РегулярноеВыражениеAPI.Заменить(Текст, ТекстМетода);
Иначе
Поз = СтрНайти(Текст, "#Область Тесты");
Если Поз > 0 Тогда
НовыйТекстМодуля = Лев(Текст, Поз - 1) + ТекстМетода + Символы.ПС + Символы.ПС + Сред(Текст, Поз);
Иначе
НовыйТекстМодуля = ТекстМетода + Символы.ПС + Символы.ПС + Текст;
КонецЕсли;
КонецЕсли;
Если НовыйТекстМодуля <> Текст Тогда
ТекстовыйДокумент.УстановитьТекст(НовыйТекстМодуля);
ТекстовыйДокумент.Записать(Файл.ПолноеИмя, КодировкаТекста.UTF8NoBOM);
Сообщить("Обновлен файл " + Файл.ПолноеИмя);
Возврат Истина;
КонецЕсли;
КонецЕсли;
Возврат Ложь;
КонецФункции
@@ -83,21 +83,32 @@
Для Каждого Совпадение Из Совпадения Цикл
СтрокаТЗ = ТЗПроцедуры.Добавить();
СтрокаТЗ.ИмяПроцедуры = НРЕГ(Совпадение.Группы[1].Значение);
СтрокаТЗ.Количество = 1;
ИмяПроцедуры = НРЕГ(Совпадение.Группы[1].Значение);
СтрокаТЗ = ТЗПроцедуры.Найти(ИмяПроцедуры);
Если СтрокаТЗ = Неопределено Тогда
СтрокаТЗ = ТЗПроцедуры.Добавить();
СтрокаТЗ.ИмяПроцедуры = ИмяПроцедуры;
СтрокаТЗ.Количество = 1;
Иначе
СтрокаТЗ.Количество = СтрокаТЗ.Количество + 1;
КонецЕсли;
КонецЦикла;
КоличествоПроцедур = ТЗПроцедуры.Количество();
ТЗПроцедуры.Свернуть("ИмяПроцедуры", "Количество");
КоличествоПроцедур = Совпадения.Количество();
// ТЗПроцедуры.Свернуть("ИмяПроцедуры", "Количество"); // TODO: Вернуть свернуть
КоличествоУникальных = ТЗПроцедуры.Количество();
Если КоличествоПроцедур <> КоличествоУникальных Тогда
ТекстОшибки = СтрШаблон("В файле '%1' обнаружены неуникальные имена методов " + Символы.ПС, ПутьКФайлуМодуля);
Для Каждого СтрокаТЗ Из ТЗПроцедуры Цикл
Для Каждого СтрокаТЗ Из ТЗПроцедуры Цикл // TODO: можно ускорить отсортировав и прервавшись
ТекстОшибки = ТекстОшибки + ?(СтрокаТЗ.Количество > 1, СтрокаТЗ.ИмяПроцедуры + Символы.ПС, "");
+230
View File
@@ -0,0 +1,230 @@
135
29
91
60
30
120
61
31
92
121
130
131
133
8
9
10
11
134
13
14
15
16
5
62
32
132
7
8
63
10
11
64
33
93
122
5
6
7
8
12
65
34
94
123
5
6
7
8
13
66
35
95
4
5
6
7
8
14
96
67
36
4
5
15
68
37
97
4
5
6
9
17
124
69
38
98
4
5
6
19
70
39
99
4
5
6
7
20
71
40
100
4
5
6
21
72
41
22
23
73
42
24
74
43
101
25
75
102
44
4
5
6
26
114
128
-1
45
103
76
46
4
77
47
104
4
5
6
7
8
9
10
11
12
13
14
15
16
5
78
48
6
7
8
79
10
11
80
49
105
4
5
6
7
8
12
81
50
106
4
5
6
7
8
13
82
51
107
4
5
6
7
8
14
108
83
52
4
5
15
84
53
109
4
5
6
9
17
125
85
54
110
4
5
6
19
86
55
111
4
5
6
7
20
87
56
112
4
5
6
21
88
57
22
23
89
58
24
90
59
113
25
1
3
2
4
5
6
26
115
129
@@ -1,6 +1,7 @@
#Использовать asserts
#Использовать logos
#Использовать tempfiles
#Использовать semver
Перем юТест;
Перем Лог;
@@ -27,7 +28,8 @@
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоСценарийИсправлениеНеКаноническогоНаписанияИсправляетТолькоНаписание");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоСинхронизацияОбъектовМетаданныхВызываетИсключение");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЗагрузкуСценариевПоИмени");
ВсеТесты.Добавить("ТестДолжен_ПроверитьБагДвижкаOscript");
Возврат ВсеТесты;
КонецФункции
@@ -66,12 +68,12 @@
Процедура ТестДолжен_ПроверитьЧтоСценарийИсправлениеНеКаноническогоНаписанияИсправляетТолькоНаписание() Экспорт
ОбъектСценария = ПолучитьСценарий("ИсправлениеНеКаноническогоНаписания.os");
ОбъектСценария = ПолучитьСценарий("ИсправлениеНеКаноническогоНаписания.os");
ИмяФайла = "ИсправлениеНеКаноническогоНаписания.bsl";
Файл = ПодготовитьИзменяемыйТестовыйФайл(ИмяФайла);
ТекстФайлаДо = ФайловыеОперации.ПрочитатьТекстФайла(Файл.ПолноеИмя);
Результат = ОбъектСценария.ОбработатьФайл(Файл, Файл.Путь, ПолучитьДополнительныеНастройки());
Результат = ОбъектСценария.ОбработатьФайл(Файл, Файл.Путь, ПолучитьДополнительныеНастройки());
ТекстФайлаПосле = ФайловыеОперации.ПрочитатьТекстФайла(Файл.ПолноеИмя);
// текст изменен
@@ -180,7 +182,7 @@
Процедура ТестДолжен_ПроверитьЗагрузкуСценариевПоИмени() Экспорт
Файл = Новый Файл(МенеджерВременныхФайлов.СоздатьФайл("bsl"));
Файл = Новый Файл(МенеджерВременныхФайлов.СоздатьФайл("bsl"));
Имена = Новый Массив;
@@ -200,7 +202,7 @@
Имена.Добавить("РазборОтчетовОбработокРасширений.os");
Сценарии = СценарииОбработки.Загрузить(Файл.Путь, "", Имена);
Ожидаем.Что(Сценарии.Количество(), "С массивом загружаемых сценариев что-то пошло не так").Равно(2);
КонецПроцедуры
#КонецОбласти
@@ -215,7 +217,7 @@
ВызываетсяИсключениеСТекстом(ОбъектСценария, Файл, "Имя каталога Ancillary отличается от метаданного ancillary");
// удаление типа без удаления файлов
ВызываетсяИсключениеСТекстом(ОбъектСценария, Файл, "Необходимо удалить файлы");
// базовые элементы
// базовые элементы
ВызываетсяИсключениеСТекстом(ОбъектСценария, Файл, "Отсутствует каталог ChartsOfCharacteristicTypes");
ВызываетсяИсключениеСТекстом(ОбъектСценария, Файл, "Отсутствует каталог Catalogs");
ВызываетсяИсключениеСТекстом(ОбъектСценария, Файл, "Отсутствует каталог CommandGroups");
@@ -312,6 +314,46 @@
КонецПроцедуры
Процедура ТестДолжен_ПроверитьБагДвижкаOscript() Экспорт
Если ВерсияOscriptБольше1_0_21() Тогда
Чтение = Новый ЧтениеТекста(Фикстура("ТаблицаЗначений.txt"), "UTF-8");
ТЧ = Новый ТаблицаЗначений;
ТЧ.Колонки.Добавить("Значение");
ТЧ.Колонки.Добавить("Количество");
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
СтрТЧ = ТЧ.Добавить();
СтрТЧ.Значение = СокрЛП(Строка); // с преобразованием в число проблема будет та же самая
СтрТЧ.Количество = 1;
Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
ТЧ.Свернуть("Значение", "Количество");
Строка = ТЧ.Найти("53", "Значение");
Ожидаем.Что(Строка.Количество).Больше(1);
КонецЕсли;
// когда этот тест начнет падать надо сделать
// 1. Удалить из зависимостей пакета sevmer
// 2. Удалить директивы #использовть semver
// 3. Удалить функцию ВерсияOscriptБольше1_0_21
// 4. Удалить тест
// 5. Вернуть использование метода свернуть по тегу "TODO: Вернуть свернуть"
КонецПроцедуры
Функция ВерсияOscriptБольше1_0_21()
Возврат Версии.ВерсияБольше(СокрЛП(Новый СистемнаяИнформация().Версия), "1.0.21");
КонецФункции
Процедура ВключитьПоказОтладки()
Лог.УстановитьУровень(УровниЛога.Отладка);
КонецПроцедуры
@@ -324,6 +366,11 @@
Возврат ОбъединитьПути(КаталогИсходников(), "tests\fixtures");
КонецФункции
Функция Фикстура(ПутьВКаталогеФикстур)
Возврат ОбъединитьПути(КаталогТестовыхФикстур(), ПутьВКаталогеФикстур)
КонецФункции
Функция КаталогИсходников()
Возврат ОбъединитьПути(ТекущийСценарий().Каталог, "..");
КонецФункции
@@ -336,7 +383,7 @@
Функция ПолучитьДополнительныеНастройки()
УправлениеНастройками = МенеджерНастроек.НастройкиРепозитория(ТекущийКаталог(), Ложь);
УправлениеНастройками = МенеджерНастроек.НастройкиРепозитория(ТекущийКаталог(), Ложь);
Настройка = МенеджерНастроек.НастройкиПроекта().Получить("НастройкиСценариев");
ДополнительныеНастройки = Новый Структура("Лог, Настройки, ИзмененныеКаталоги", Лог, Настройка, Новый Массив());