Review replication: Difference between revisions

From Svacer Wiki
mNo edit summary
(поправлена структура документа и форматирование)
Line 48: Line 48:
'''Шаги решения:'''
'''Шаги решения:'''


* (опционально, но рекомендуется) Выгрузить разметку с ветки в файл, используя команду:
1. (Опционально, но рекомендуется) Выгрузить разметку с ветки в файл, используя команду:


  svacer markup2 --host=<nowiki>http://localhost:8080</nowiki> --user admin --password admin export --project myproject --branch master  --uncompressed --format json --export-all /tmp/myproject.json
  svacer markup2 --host=<nowiki>http://localhost:8080</nowiki> --user admin --password admin export --project myproject --branch master  --uncompressed --format json --export-all /tmp/myproject.json
2. Написать правила переноса разметки (предикатов переноса) в файл <code>/tmp/map.txt</code>


* написать правила переноса разметки в файл <code>/tmp/map.txt</code> (формат будет описан ниже)
3. Если разметка была выгружена (шаг 1), то применить утилиту <code>reviewer</code> с загрузкой данных из файла (флаг <code>--html</code> создаст дополнительно HTML с информацией об изменениях , имя файла <code>/tmp/out.json.html</code>):
* (если разметка '''была выгружена''') применить утилиту <code>reviewer</code> с загрузкой данных из файла (флаг <code>--html</code> создаст дополнительно HTML с информацией об изменениях , имя файла <code>/tmp/out.json.html</code>):


  reviewer replicate --file /tmp/myproject.json --rule /tmp/map.txt --html /tmp/out.json
  reviewer replicate --file /tmp/myproject.json --rule /tmp/map.txt --html /tmp/out.json
 
4. Если разметка не была выгружена (шаг 1 пропущен) применить утилиту <code>reviewer</code> с загрузкой данных с сервера (флаг <code>--html</code> создаст дополнительно HTML с информацией об изменениях , имя файла <code>/tmp/out.json.html</code>):
* ('''без выгрузки''' разметки) применить утилиту <code>reviewer</code> с загрузкой данных с сервера (флаг <code>--html</code> создаст дополнительно HTML с информацией об изменениях , имя файла <code>/tmp/out.json.html</code>):


  reviewer --host=http://localhost:8080 --user admin --password admin replicate --project myproject --branch master --rule /tmp/map.txt --html /tmp/out.json
  reviewer --host=http://localhost:8080 --user admin --password admin replicate --project myproject --branch master --rule /tmp/map.txt --html /tmp/out.json
5. Проанализировать созданный файл <code>/tmp/out.json.html</code>


* просмотреть созданный файл <code>/tmp/out.json.html</code>
6. Если результат устраивает, то загрузить обновленную разметку в сервер:
* если результат устраивает, то загрузить обновленную разметку в сервер:
 
  svacer markup2 --host=<nowiki>http://localhost:8080</nowiki> --user admin --password admin import --project myproject --branch master /tmp/out.json
  svacer markup2 --host=<nowiki>http://localhost:8080</nowiki> --user admin --password admin import --project myproject --branch master /tmp/out.json
'''<u>''Примечания''</u>'''


==== Пояснения ====
Разметка в Svacer привязана к инвариантам. Инвариант это некоторый хэш, формируемый из полей предупреждения. Алгоритм формирования хэша описан здесь: [[Help:Match|формирование инвариантов]]. В рамках одного снимка все инварианты всегда уникальны.
Разметка в Svacer привязана к инвариантам. Инвариант это некоторый хэш, формируемый из полей предупреждения. Алгоритм формирования хэша описан здесь: [[Help:Match|формирование инвариантов]]. В рамках одного снимка все инварианты всегда уникальны.


Line 83: Line 81:


==== Файл задания предикатов переноса ====
==== Файл задания предикатов переноса ====
Формат файла: UTF-8
Формат файла: UTF-8. Правила разделяются <code>;;</code>. В качестве комментариев допустимы <code>/**/ и //</code>
 
Правила разделяются <code>;;</code>
 
В качестве комментариев допустимы <code>/**/ и //</code>
 
Правила - это булевы выражение в синтаксисе [https://expr-lang.org/docs/language-definition go-expr] ,  выражения использует операторы <code>&& , ||, !, скобки</code> и
 
следующие дополнительные предикаты:
 
 
 
* <code>unprocessed()</code>
 
проверка, что target еще не содержит разметки. Рекомендуется использовать, чтобы избежать перезаписи разметки, если несколько правил сработали.
 
* <code>processed()</code>
 
проверка, что target уже содержит какую-либо не дефолтную разметку
 
* <code>match_loc(field1, field2, ...)</code>
 
проверка, содержат ли locations в source и target хотя бы один общий location, какой совпадает по указанным полям
 
возможные поля: <code>warnclass, function, details, invariant, line, file, mtid, tool, lang</code>
 
Пример: <code>match_loc(warnclass,file,lang,tool,line)</code>
 
* <code>match_loc_strict(field1, field2, ...)</code>
 
 проверка, содержат ли locations source и target одинаковые location по указанным полям
 
 Пример: <code>match_loc_strict(warnclass,file,lang,tool,line)</code>
 
* <code>match_source_re (field, value)</code>
 
 проверка, содержит ли location в source запись где field совпадает с value. Value - Golang regexp
 
* <code>match_target_re (field, value)</code>
 
 проверка, содержит ли location в target запись где field совпадает с value. Value - Golang regexp
 
* <code>source_review(status[, severity, action])</code>
 
 проверка, если разметка source соответствует указанным параметрам
 
 <code>severity, action</code> можно опускать
 
 шаблон <code>"*"</code> соответствует всему
 
* <code>target_review(status[, severity, action])</code>
 
 проверка, если разметка target соответствует указанным параметрам
 
 <code>severity, action</code> можно опускать


 шаблон <code>"*"</code> соответствует всему
Правила - это булевы выражение в синтаксисе [https://expr-lang.org/docs/language-definition go-expr] ,  выражения использует операторы <code>&& , ||, !, скобки</code> и следующие дополнительные предикаты:


* <code>match_source_range (lower_bound,upper_bound)</code>
* <code>unprocessed()</code> - проверка, что target еще не содержит разметки. Рекомендуется использовать, чтобы избежать перезаписи разметки, если несколько правил сработали;


проверка, если в source есть location где line попадает в указанный диапазон. Значение -1 означает отсутствие границы   
* <code>processed()</code> - проверка, что target уже содержит какую-либо не дефолтную разметку;


* <code>match_target_range (lower_bound,upper_bound)</code>
* <code>match_loc(field1, field2, ...)</code> - проверка, содержат ли locations в source и target хотя бы один общий location, какой совпадает по указанным полям. Возможные поля: <code>warnclass, function, details, invariant, line, file, mtid, tool, lang</code>
<u>Пример</u>: <code>match_loc(warnclass,file,lang,tool,line)</code>
* <code>match_loc_strict(field1, field2, ...)</code>  - проверка, содержат ли locations source и target одинаковые location по указанным полям


проверка, если в target есть location, где line попадает в указанный диапазон. Значение -1 означает отсутствие границы
     <u>Пример</u>: <code>match_loc_strict(warnclass,file,lang,tool,line)</code>


* <code>match_suffix_re (field, source_prefix[,target_prefix])</code>
* <code>match_source_re (field, value)</code> - проверка, содержит ли location в source запись, где field совпадает с value. Value - Golang regexp;


проверка, есть ли <code>location</code> в <code>source</code> и <code>target</code>, какой содержит общий суффикс. Суффикс вычисляется путем отрезания префикса <code>source_prefix</code> и <code>target_prefix</code>. Если target_prefix не указан, то считается что он равен source_prefix. Префикс определяется как Go regexp
* <code>match_target_re (field, value)</code> - проверка, содержит ли location в target запись где field совпадает с value. Value - Golang regexp;


* <code>match_source_id (id1, id2, ....)</code>
* <code>source_review(status[, severity, action])</code> - проверка, если разметка source соответствует указанным параметрам. <code>severity, action</code> можно опускать, шаблон <code>"*"</code> соответствует всему;


проверка, если внутренний id source разметки совпадает с одним из аргументов
* <code>target_review(status[, severity, action])</code> - проверка, если разметка target соответствует указанным параметрам. <code>severity, action</code> можно опускать, шаблон <code>"*"</code> соответствует всему;


* <code>match_target_id (id1, id2, ....)</code>
* <code>match_source_range (lower_bound,upper_bound)</code> - проверка, если в source есть location, где line попадает в указанный диапазон. Значение <code>-1</code> означает отсутствие границы;   


проверка, если внутренний id target разметки совпадает с одним из аргументов
* <code>match_target_range (lower_bound,upper_bound)</code> - проверка, если в target есть location, где line попадает в указанный диапазон. Значение <code>-1</code> означает отсутствие границы;


* <code>source_review_ct() time.Time</code>
* <code>match_suffix_re (field, source_prefix[,target_prefix])</code> - проверка, есть ли location в source и target, какой содержит общий суффикс. Суффикс вычисляется путем отрезания префикса source_prefix и target_prefix. Если target_prefix не указан, то считается, что он равен source_prefix. Префикс определяется как Go regexp;


возвращает время создания разметки в source
* <code>match_source_id (id1, id2, ....)</code> - проверка, если внутренний id source разметки совпадает с одним из аргументов;


* <code>target_review_ct() time.Time</code>
* <code>match_target_id (id1, id2, ....)</code> - проверка, если внутренний id target разметки совпадает с одним из аргументов;


возвращает время создания разметки в target
* <code>source_review_ct() time.Time</code> - возвращает время создания разметки в source;


* <code>source_reviewed_by() string</code>
* <code>target_review_ct() time.Time</code> - возвращает время создания разметки в target;


возвращает автора разметки в source
* <code>source_reviewed_by() string</code> - возвращает автора разметки в source;


* <code>target_reviewed_by() string</code>
* <code>target_reviewed_by() string</code> - возвращает автора разметки в target.


возвращает автора разметки в target


Пример:
<u>Пример</u>:
  // Перенос разметки для Go, где поменялся формат поля function в последних Svace
  // Перенос разметки для Go, где поменялся формат поля function в последних Svace
   
   
Line 187: Line 132:
При использовании опции <code>--html</code>утилита формирует HTML файл с информацией о разметке и операциях по переносу. Файл предназначен для отладки процесса переноса. В будущем, в Svacer UI будет предусмотрен специальный интерфейс для просмотра результатов переноса.  
При использовании опции <code>--html</code>утилита формирует HTML файл с информацией о разметке и операциях по переносу. Файл предназначен для отладки процесса переноса. В будущем, в Svacer UI будет предусмотрен специальный интерфейс для просмотра результатов переноса.  
[[File:ReviewerHTML1.png|none|thumb]]
[[File:ReviewerHTML1.png|none|thumb]]
При наличии переноса разметки в столбце с Review будет запись Review Source с ссылкой на элемент, откуда была перенесена разметка
При наличии переноса разметки в столбце с Review будет запись Review Source с ссылкой на элемент, откуда была перенесена разметка.
[[File:ReviewerHTMLReport2.png|none|thumb]]При раскрытии элемента <code>Review Source</code> будут представлены основные поля location-ов, соответствующих исходной разметки, откуда был сделан перенос.
[[File:ReviewerHTMLReport2.png|none|thumb]]При раскрытии элемента Review Source будут представлены основные поля location-ов, соответствующих исходной разметке, откуда был сделан перенос.

Revision as of 15:25, 4 March 2025

Репликация разметки по правилам (экспериментальная функциональность)

При использовании разных версий Svace (или иных анализаторов), разных настроек CI/CD и прочих факторах возможны ситуации, когда снимки (snapshots) в рамках одной ветки (branch) могут иметь различные инварианты и разметка автоматически не переносится. Для решения задачи переноса разметки в таких случаях разработана утилита reviewer, которая позволяет применить декларативно описанные правила переноса к существующей разметке. В дальнейшем данная функциональность будет включена в Svacer и доступна в веб-интерфейсе.

Описание утилиты

Утилита reviewer предназначена для Svacer версии 10 и выше.

NAME:
   reviewer - Svacer review help tool

USAGE:
   reviewer [global options] command [command options] [arguments...]

COMMANDS:
   syntax     Prints help information about rule syntax
   replicate  Replicate non-empty review to invariants according to rules
   help, h    Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug              Enabled debug output (default: false)
   --log-file value     Define log file for output
   --host value         Defines URL to svacer server. Format: http://host:port
   --user value         User login. When using env variable SVACER_AUTH_CREDS the format is SVACER_AUTH_CREDS=<login>:<password> (default: admin) [$SVACER_AUTH_CREDS]
   --password value     User password (default: admin)
   --ldap_server value  Server for LDAP authentication [$SVACER_LDAP_SERVER]
   --token value        Defines access token for svacer server [$SVACER_AUTH_TOKEN]
   --help, -h           show help

Основная команда, это replicate - она позволяет применить декларативные правила к разметке, полученной либо с сервера, либо из файла, куда ранее она была выгружена командой svacer markup2 export.

NAME:
   reviewer replicate - Replicate non-empty review to invariants according to rules

USAGE:
   reviewer replicate [command options] <file name> - path to output file with applied rules

OPTIONS:
   --project value  Project name or id
   --branch value   Branch name or id (default: master)
   --file value     Load review from file instead of server. File must be in 'json with new line separator' format. File may be gzipped (must have *.gz extension)
   --rule value     Path to file containing replicate rules
   --html           Produce HTML report showing applied changes.Report wil have name <file name>.html (default: false)
   --verbose        Verbose output of rule applications (default: false)
   --process-all    Process all reviews, even with non-default values (default: false)
   --skip-comments  Skip comments while replicating review information (default: false)
   --skip-status    Skip review status and copy only comments while replicating review information (default: false)
   --help, -h       show help

Шаги применения утилиты

Задача: В проекте myproject на ветке master необходимо перенести существующую разметку по некоторым правилам. Сервер запущен на localhost на порте 8080.

Шаги решения:

1. (Опционально, но рекомендуется) Выгрузить разметку с ветки в файл, используя команду:

svacer markup2 --host=http://localhost:8080 --user admin --password admin export --project myproject --branch master  --uncompressed --format json --export-all /tmp/myproject.json

2. Написать правила переноса разметки (предикатов переноса) в файл /tmp/map.txt

3. Если разметка была выгружена (шаг 1), то применить утилиту reviewer с загрузкой данных из файла (флаг --html создаст дополнительно HTML с информацией об изменениях , имя файла /tmp/out.json.html):

reviewer replicate --file /tmp/myproject.json --rule /tmp/map.txt --html /tmp/out.json

4. Если разметка не была выгружена (шаг 1 пропущен) применить утилиту reviewer с загрузкой данных с сервера (флаг --html создаст дополнительно HTML с информацией об изменениях , имя файла /tmp/out.json.html):

reviewer --host=http://localhost:8080 --user admin --password admin replicate --project myproject --branch master --rule /tmp/map.txt --html /tmp/out.json

5. Проанализировать созданный файл /tmp/out.json.html

6. Если результат устраивает, то загрузить обновленную разметку в сервер:

svacer markup2 --host=http://localhost:8080 --user admin --password admin import --project myproject --branch master /tmp/out.json

Примечания

Разметка в Svacer привязана к инвариантам. Инвариант это некоторый хэш, формируемый из полей предупреждения. Алгоритм формирования хэша описан здесь: формирование инвариантов. В рамках одного снимка все инварианты всегда уникальны.

Команда markup2 export с флагом --export-all выгружает все инварианты с ветки с информацией о разметке и комментариях.

При экспорте, разметка на инварианте представлена как объект соответствующей схеме, описанной здесь Markup2. Технически - это:

  • статус (тройка status, severity, action)
  • набор комментариев
  • массив location-ов, которые определяют множество мест, имеющих один и тот же инвариант.

Алгоритм переноса разметки

Входные данные (разметка), полученные из файла или с сервера разбиваются на два вектора source и target. В source включаются все элементы с разметкой отличной от разметки по умолчанию. В target включаются все оставшиеся элементы. Если указана опция --process-all , то в source и target включаются все элементы (данная опция предназначена для случаев, если мы хотим заместить существующую разметку)

Процедура проходит по всем парам (source_item,target_item) и для каждой пары вычисляет предикаты из файла с правилами в порядке их определения. Если какой либо предикат вычислен в true, то происходит копирование статусов разметки и комментариев с source_item на target_item.Во избежание перезаписи разметки можно в правилах использовать предикат unprocessed() описанный ниже.

Файл задания предикатов переноса

Формат файла: UTF-8. Правила разделяются ;;. В качестве комментариев допустимы /**/ и //

Правила - это булевы выражение в синтаксисе go-expr , выражения использует операторы && , ||, !, скобки и следующие дополнительные предикаты:

  • unprocessed() - проверка, что target еще не содержит разметки. Рекомендуется использовать, чтобы избежать перезаписи разметки, если несколько правил сработали;
  • processed() - проверка, что target уже содержит какую-либо не дефолтную разметку;
  • match_loc(field1, field2, ...) - проверка, содержат ли locations в source и target хотя бы один общий location, какой совпадает по указанным полям. Возможные поля: warnclass, function, details, invariant, line, file, mtid, tool, lang

Пример: match_loc(warnclass,file,lang,tool,line)

  • match_loc_strict(field1, field2, ...)  - проверка, содержат ли locations source и target одинаковые location по указанным полям

  Пример: match_loc_strict(warnclass,file,lang,tool,line)

  • match_source_re (field, value) - проверка, содержит ли location в source запись, где field совпадает с value. Value - Golang regexp;
  • match_target_re (field, value) - проверка, содержит ли location в target запись где field совпадает с value. Value - Golang regexp;
  • source_review(status[, severity, action]) - проверка, если разметка source соответствует указанным параметрам. severity, action можно опускать, шаблон "*" соответствует всему;
  • target_review(status[, severity, action]) - проверка, если разметка target соответствует указанным параметрам. severity, action можно опускать, шаблон "*" соответствует всему;
  • match_source_range (lower_bound,upper_bound) - проверка, если в source есть location, где line попадает в указанный диапазон. Значение -1 означает отсутствие границы;   
  • match_target_range (lower_bound,upper_bound) - проверка, если в target есть location, где line попадает в указанный диапазон. Значение -1 означает отсутствие границы;
  • match_suffix_re (field, source_prefix[,target_prefix]) - проверка, есть ли location в source и target, какой содержит общий суффикс. Суффикс вычисляется путем отрезания префикса source_prefix и target_prefix. Если target_prefix не указан, то считается, что он равен source_prefix. Префикс определяется как Go regexp;
  • match_source_id (id1, id2, ....) - проверка, если внутренний id source разметки совпадает с одним из аргументов;
  • match_target_id (id1, id2, ....) - проверка, если внутренний id target разметки совпадает с одним из аргументов;
  • source_review_ct() time.Time - возвращает время создания разметки в source;
  • target_review_ct() time.Time - возвращает время создания разметки в target;
  • source_reviewed_by() string - возвращает автора разметки в source;
  • target_reviewed_by() string - возвращает автора разметки в target.


Пример:

// Перенос разметки для Go, где поменялся формат поля function в последних Svace

unprocessed() &&  // ensure target has no review
        match_loc(warnclass,file,lang,tool,mtid, line) && // ensure main fields are the same
        match_suffix_re (function, "(.+/)" /* regexp for prefix */ ) // trim prefix and match suffix

HTML отчет о результатах переноса

При использовании опции --htmlутилита формирует HTML файл с информацией о разметке и операциях по переносу. Файл предназначен для отладки процесса переноса. В будущем, в Svacer UI будет предусмотрен специальный интерфейс для просмотра результатов переноса.

При наличии переноса разметки в столбце с Review будет запись Review Source с ссылкой на элемент, откуда была перенесена разметка.

При раскрытии элемента Review Source будут представлены основные поля location-ов, соответствующих исходной разметке, откуда был сделан перенос.