Review replication: Difference between revisions
mNo edit summary |
Mitrofanov (talk | contribs) No edit summary |
||
Line 1: | Line 1: | ||
== Репликация разметки по правилам (экспериментальная функциональность) == | == Репликация разметки по правилам (экспериментальная функциональность) == | ||
При использовании разных версий Svace (или иных анализаторов), разных настроек CI/CD и прочих факторах возможны ситуации, когда снимки (snapshots) в рамках одной ветки (branch) могут иметь различные инварианты и разметка автоматически не переносится. Для решения задачи переноса разметки в таких случаях разработана утилита <code>reviewer</code>, которая позволяет применить декларативно описанные правила переноса к существующей разметке. В дальнейшем данная функциональность будет включена в Svacer и доступна в веб интерфейсе. | При использовании разных версий Svace (или иных анализаторов), разных настроек CI/CD и прочих факторах возможны ситуации, когда снимки (snapshots) в рамках одной ветки (branch) могут иметь различные инварианты и разметка автоматически не переносится. Для решения задачи переноса разметки в таких случаях разработана утилита <code>reviewer</code>, которая позволяет применить декларативно описанные правила переноса к существующей разметке. В дальнейшем данная функциональность будет включена в Svacer и доступна в веб-интерфейсе. | ||
=== Описание утилиты === | === Описание утилиты === | ||
Line 24: | Line 24: | ||
--token value Defines access token for svacer server [$SVACER_AUTH_TOKEN] | --token value Defines access token for svacer server [$SVACER_AUTH_TOKEN] | ||
--help, -h show help | --help, -h show help | ||
Основная команда, это <code>replicate</code> - она позволяет применить декларативные правила к разметке, полученной либо с сервера либо из файла, куда ранее она была выгружена командой <code>svacer markup2 export</code>. | Основная команда, это <code>replicate</code> - она позволяет применить декларативные правила к разметке, полученной либо с сервера, либо из файла, куда ранее она была выгружена командой <code>svacer markup2 export</code>. | ||
NAME: | NAME: | ||
reviewer replicate - Replicate non-empty review to invariants according to rules | reviewer replicate - Replicate non-empty review to invariants according to rules | ||
Line 48: | Line 48: | ||
'''Шаги решения:''' | '''Шаги решения:''' | ||
* (опционально, но рекомендуется) Выгрузить разметку с | * (опционально, но рекомендуется) Выгрузить разметку с ветки в файл, используя команду: | ||
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 | ||
* написать правила переноса разметки в файл <code>/tmp/map.txt</code> (формат будет описан ниже) | * написать правила переноса разметки в файл <code>/tmp/map.txt</code> (формат будет описан ниже) | ||
* (если разметка '''была выгружена''') применить утилиту <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 | ||
* ('''без выгрузки''' разметки) применить утилиту <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 | ||
* просмотреть созданный файл <code>/tmp/out.json.html</code> | * просмотреть созданный файл <code>/tmp/out.json.html</code> | ||
* если результат устраивает, то загрузить обновленную разметку в сервер | * если результат устраивает, то загрузить обновленную разметку в сервер: | ||
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 | ||
Line 71: | Line 71: | ||
Команда <code>markup2 export</code> с флагом <code>--export-all</code> выгружает все инварианты с ветки с информацией о разметке и комментариях. | Команда <code>markup2 export</code> с флагом <code>--export-all</code> выгружает все инварианты с ветки с информацией о разметке и комментариях. | ||
При экспорте, разметка на инварианте представлена как объект соответствующей схеме описанной здесь [[Markup2]]. Технически, это статус, набор комментариев и массив location-ов, которые определяют множество мест имеющих один и тот же инвариант. | При экспорте, разметка на инварианте представлена как объект соответствующей схеме, описанной здесь [[Markup2]]. Технически, это статус, набор комментариев и массив location-ов, которые определяют множество мест, имеющих один и тот же инвариант. | ||
=== Алгоритм переноса разметки === | === Алгоритм переноса разметки === | ||
Входные данные (разметка), | Входные данные (разметка), полученные из файла или с сервера разбиваются на два вектора source и target. В source включаются все элементы с разметкой отличной от разметки по умолчанию. В target включаются все оставшиеся элементы. Если указана опция <code>--process-all</code> , то в source и target включаются все элементы (данная опция предназначена для случаев, если мы хотим заместить существующую разметку) | ||
Процедура проходит по всем парам <code>(source_item,target_item)</code> и для каждой пары вычисляет предикаты из файла с правилами в порядке их определения. Если какой либо предикат вычислен в true, то происходит копирование статусов разметки и комментариев с <code>source_item</code> на <code>target_item.</code>Во избежание перезаписи разметки можно в правилах использовать предикат <code>unprocessed()</code> описанный ниже. | Процедура проходит по всем парам <code>(source_item,target_item)</code> и для каждой пары вычисляет предикаты из файла с правилами в порядке их определения. Если какой либо предикат вычислен в true, то происходит копирование статусов разметки и комментариев с <code>source_item</code> на <code>target_item.</code>Во избежание перезаписи разметки можно в правилах использовать предикат <code>unprocessed()</code> описанный ниже. | ||
Line 92: | Line 92: | ||
<code>unprocessed()</code> | <code>unprocessed()</code> | ||
проверка, что target еще не содержит разметки. Рекомендуется использовать | проверка, что target еще не содержит разметки. Рекомендуется использовать, чтобы избежать перезаписи разметки, если несколько правил сработали. | ||
Line 151: | Line 151: | ||
<code>match_target_range (lower_bound,upper_bound)</code> | <code>match_target_range (lower_bound,upper_bound)</code> | ||
проверка, если в target есть location где line попадает в указанный диапазон. Значение -1 означает отсутствие границы | проверка, если в target есть location, где line попадает в указанный диапазон. Значение -1 означает отсутствие границы | ||
<code>match_suffix_re (field, source_prefix[,target_prefix])</code> | <code>match_suffix_re (field, source_prefix[,target_prefix])</code> | ||
проверка, есть ли <code>location</code> в <code>source</code> и <code>target</code>,какой содержит общий суффикс. Суффикс вычисляется путем отрезания префикса <code>source_prefix</code> и <code>target_prefix</code>. Если target_prefix не указан, то считается что он равен source_prefix. Префикс определяется как Go regexp | проверка, есть ли <code>location</code> в <code>source</code> и <code>target</code>, какой содержит общий суффикс. Суффикс вычисляется путем отрезания префикса <code>source_prefix</code> и <code>target_prefix</code>. Если target_prefix не указан, то считается что он равен source_prefix. Префикс определяется как Go regexp | ||
Revision as of 12:54, 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.
Шаги решения:
- (опционально, но рекомендуется) Выгрузить разметку с ветки в файл, используя команду:
svacer markup2 --host=http://localhost:8080 --user admin --password admin export --project myproject --branch master --uncompressed --format json --export-all /tmp/myproject.json
- написать правила переноса разметки в файл
/tmp/map.txt
(формат будет описан ниже) - (если разметка была выгружена) применить утилиту
reviewer
с загрузкой данных из файла (флаг--html
создаст дополнительно HTML с информацией об изменениях , имя файла/tmp/out.json.html
):
reviewer replicate --file /tmp/myproject.json --rule /tmp/map.txt --html /tmp/out.json
- (без выгрузки разметки) применить утилиту
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
- просмотреть созданный файл
/tmp/out.json.html
- если результат устраивает, то загрузить обновленную разметку в сервер:
svacer markup2 --host=http://localhost:8080 --user admin --password admin import --project myproject --branch master /tmp/out.json
Пояснения
Разметка в Svacer привязана к инвариантам. Инвариант это некоторый хэш, формируемый из полей предупреждения. Алгоритм формирования хэша описан здесь: формирование инвариантов. В рамках одного снимка все инварианты всегда уникальны.
Команда markup2 export
с флагом --export-all
выгружает все инварианты с ветки с информацией о разметке и комментариях.
При экспорте, разметка на инварианте представлена как объект соответствующей схеме, описанной здесь Markup2. Технически, это статус, набор комментариев и массив location-ов, которые определяют множество мест, имеющих один и тот же инвариант.
Алгоритм переноса разметки
Входные данные (разметка), полученные из файла или с сервера разбиваются на два вектора source и target. В source включаются все элементы с разметкой отличной от разметки по умолчанию. В target включаются все оставшиеся элементы. Если указана опция --process-all
, то в source и target включаются все элементы (данная опция предназначена для случаев, если мы хотим заместить существующую разметку)
Процедура проходит по всем парам (source_item,target_item)
и для каждой пары вычисляет предикаты из файла с правилами в порядке их определения. Если какой либо предикат вычислен в true, то происходит копирование статусов разметки и комментариев с source_item
на target_item.
Во избежание перезаписи разметки можно в правилах использовать предикат unprocessed()
описанный ниже.
Файл задания предикатов переноса
Формат файла: UTF-8
Правила разделяются ;;
В качестве комментариев допустимы /**/ и //
Правила - это выражение в синтаксисе (https://expr-lang.org/docs/language-definition), выражения использует операторы && , ||, !, скобки
и
следующие дополнительные предикаты:
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 разметки совпадает с одним из аргументов
Пример:
// Перенос разметки для 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