Системные требования
CPU
| x86-64. Для больших проектов рекомендуется не менее 8 ядер | |
RAM |
| |
HDD
|
От 1 ГБ до нескольких ТБ при хранении множества снимков больших проектов
| |
OS
|
Функциональность сервера при запуске на Windows ограничена:
| |
Browser
| Для работы с веб-интерфейсом
|
Создание кейсов в системах отслеживания ошибок
Gitlab
На сервере, где будет выполняться хук, должен быть установлен python3.
- Скачайте и распакуйте архив со скриптом и конфигом хука:
- Сделайте файл gitlab-create-issue.py исполняемым
chmod u+x gitlab-create-issue.py
- Поменяйте в файле gitlab-create-issue.py путь к интерпретатору python3, если в вашей системе он не такой, как указано там в первой строчке
- В файле hooks.json поменяйте URL гитлаба в args
- В качестве второго аргумента args впишите ID проекта гитлаба. Его можно найти на главной странице проекта, под именем

- В гитлабе создайте Access Token для проекта в Settings > Access Tokens. Выберите роль 'Reporter', scope — 'api'

- Созданный токен впишите как третий аргумент в args
- В аргументе cmd этого же файла укажите полный путь к скрипту gitlab-create-issue.py
- Если вы настраиваете хук на Windows, то вместо этого укажите в cmd путь к интерпретатору python (или просто имя, если он есть в PATH), а в качестве первого аргумента в args добавьте путь к скрипту хука
"cmd": "python",
"args": [
"C:\\svacer-hooks\\gitlab-create-issue.py",
"https://gitlab.example.com",
...
- Запустите svacer с указанием пути к файлу hooks.json в аргументе hooks
svacer server --hooks=/home/user/svacer/hooks.json
- Хук будет доступен в UI Svacer, на правой панели, в Details > Hooks > Run

- После нажатия на хук он выполнится и в указанном проекте гитлаба будет создан новый кейс с информацией из предупреждения в заголовке и описании, в качестве лейбла (тега) будет задан severity чекера

Jira
На сервере, где будет выполняться хук, должен быть установлен python3.
- Скачайте и распакуйте архив со скриптом и конфигом хука:
- Сделайте файл jira-create-issue.py исполняемым
chmod u+x jira-create-issue.py
- Поменяйте в файле jira-create-issue.py путь к интерпретатору python3, если в вашей системе он не такой, как указано там в первой строчке
- В файле hooks.json поменяйте URL джиры в args
- В качестве второго аргумента args впишите ID проекта джиры. Его можно найти на главной странице проекта в графе Key, или взять из URL проекта

- Создайте Personal Access Token для аккаунта, от которого будут создаваться кейсы в Profile > Personal Access Tokens > Create Token. У этого аккаунта должны быть права на создание кейсов в соответствующем проекте
- Созданный токен впишите как третий аргумент в args
- В качестве четвертого аргумента в args укажите тип кейса, который будет создаваться. Посмотреть какие типы доступны в вашем проекте можно при создании кейса в поле issue type

- В аргументе cmd этого же файла укажите полный путь к скрипту jira-create-issue.py
- Если вы настраиваете хук на Windows, то вместо этого укажите в cmd путь к интерпретатору python (или просто имя, если он есть в PATH), а в качестве первого аргумента в args добавьте путь к скрипту хука
"cmd": "python",
"args": [
"C:\\svacer-hooks\\jira-create-issue.py",
"https://jira.example.com",
...
- Запустите svacer с указанием пути к файлу hooks.json в аргументе hooks
svacer server --hooks=/home/user/svacer/hooks.json
- Хук будет доступен в UI Svacer, на правой панели, в Details > Hooks > Run

- После нажатия на хук он выполнится и в указанном проекте джиры будет создан новый кейс с информацией из предупреждения в заголовке и описании, в качестве лейбла (тега) будет задан severity чекера

Redmine
На сервере, где будет выполняться хук, должен быть установлен python3.
- Скачайте и распакуйте архив со скриптом и конфигом хука:
- Сделайте файл redmine-create-issue.py исполняемым
chmod u+x redmine-create-issue.py
- Поменяйте в файле redmine-create-issue.py путь к интерпретатору python3, если в вашей системе он не такой, как указано там в первой строчке
- В файле hooks.json поменяйте URL редмайна в args
- В качестве второго аргумента args впишите ID проекта редмайна. Его можно найти в настройках проекта, или взять из URL

- В Redmine должен быть включен REST API в Administration > Settings > API

- Когда REST API включен, вы найдете свой API-ключ на странице аккаунта (/my/account), в правой панели

- Впишите этот ключ как третий аргумент в args
- В аргументе cmd этого же файла укажите полный путь к скрипту redmine-create-issue.py
- Если вы настраиваете хук на Windows, то вместо этого укажите в cmd путь к интерпретатору python (или просто имя, если он есть в PATH), а в качестве первого аргумента в args добавьте путь к скрипту хука
"cmd": "python",
"args": [
"C:\\svacer-hooks\\redmine-create-issue.py",
"https://redmine.example.com",
...
- Запустите svacer с указанием пути к файлу hooks.json в аргументе hooks
svacer server --hooks=/home/user/svacer/hooks.json
- Хук будет доступен в UI Svacer, на правой панели, в Details > Hooks > Run

- После нажатия на хук он выполнится и в указанном проекте редмайна будет создан новый кейс с информацией из предупреждения в заголовке и описании

Примеры использования public REST API
Получение URL загруженного снимка
Этот пример работает только с python3 и не работает при аутентификации в Svacer через LDAP.
Скачайте и распакуйте
Запрос:
python get_link.py --url http://svacer.example.com:8080 --user admin --password admin --project bash
Ответ:
http://svacer.example.com:8080/mode/review/project/0fd645aa-8e70-4a4f-b68b-766c4f337bf2/branch/8925df5a-7a98-4f07-bc88-ee4ea5b43813/snapshot/e3367efa-a804-4c05-9a7a-a7cb052bef1d
Примеры использования фильтров в public api
Данные фильтры служат только для ограничения вывода некоторых методов в public api. Они являются отдельной сущностью, наравне с глобальными фильтрами и пользовательскими фильтрами. Основное отличие в том, что время их жизни соответствует одному запросу, в котором они заданы.
Вспомогательные модули
В некоторых примерах API используется фильтр, с помощью которого можно ограничить вывод данных и получить более точные результаты. Для работы с этим фильтром используются следующие классы:
import requests
from requests import auth
from requests.models import HTTPBasicAuth
import json
from dataclasses import dataclass
import sys
import base64
def printerr(text):
#print in stderr and exit
print(f"{text}", file=sys.stderr, flush=True)
exit()
@dataclass
class ProjectFilter:
id: str
name: str
class ProjectFilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
@dataclass
class BranchFilter:
id: str
name: str
class BranchFilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
@dataclass
class SnapshotFilter:
id: str
name: str
class SnapshotFilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
@dataclass
class MarkerFilter:
severity: str
file: str
checker: str
review: str
class MarkerFilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
@dataclass
class Filter:
project: ProjectFilter
branch: BranchFilter
snapshot: SnapshotFilter
marker: MarkerFilter
class FilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
def CreateFilterParam(filter: Filter):
jsoned = FilterEncoder().encode(filter)
b64ed = base64.b64encode(jsoned.encode("utf-8"))
return b64ed.decode("utf-8")
Принцип использования классов следующий:
- Создается экземпляр нужного класса XXXXFilter
- Создается base64 строка на основе объекта пункта 1, которая в дальнейшем передается в url запросе. Для этого используется метод CreateFilterParam()
Например. Для создания фильтра, ограничивающего множество проектов выражением darpa*, можно использовать следующие строчки кода:
f: Filter = Filter(ProjectFilter(id="", name="darpa*"), None, None, None) param = CreateFilterParam(f)
Для проекта, ветки и снимка можно указать как имя так и ID. Имя можно указать с использованием регулярного выражения. ID необходимо указать полностью.
Метод /api/public/login
Данный класс может быть использован для соединения с сервером Svacer. В данном модуле демонстрируется взаимодействие с методом /api/public/login.
import requests
class SvacerClient:
def __init__(self, host, user, password):
"""
Initialize the Svacer client
"""
self.host = host
self.user = user
self.password = password
self.token = None
self.auth_header = None
self.session = requests.Session() # Use session for connection pooling
self.set_auth_token()
def set_auth_token(self):
"""
Get authorization token using /api/public/login and setup in session
"""
try:
response = requests.post(
url=f"{self.host}/api/public/login",
json={
"login":self.user,
"password":self.password,
},
verify=False
)
response.raise_for_status() # Raise an exception for bad status codes
body = response.json()
self.token = body["token"]
self.auth_header = {'Authorization': f'Bearer {self.token}'}
# Set the authorization header in the session
self.session.headers.update(self.auth_header)
return self.token
except requests.exceptions.RequestException as e:
raise Exception(f"Failed to get authentication token: {e}")
except KeyError as e:
raise Exception(f"Token not found in response: {e}")
def post(self, endpoint, data=None, json=None, **kwargs):
"""
Make a POST request to the API
"""
if self.auth_header is None:
raise Exception("No authentication token available. Call get_auth_token() first.")
url = f"{self.host}{endpoint}"
try:
response = self.session.post(
url,
data=data,
json=json,
verify=False,
**kwargs
)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
raise Exception(f"POST request failed: {e}")
def get(self, endpoint, params=None, **kwargs):
"""
Make a GET request to the API
"""
if self.auth_header is None:
raise Exception("No authentication token available. Call get_auth_token() first.")
url = f"{self.host}{endpoint}"
try:
response = self.session.get(
url,
params=params,
verify=False,
**kwargs
)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
raise Exception(f"GET request failed: {e}")
Метод /api/public/projects
В данном примере выводится в формате json список проектов, имя которых соответствует регулярному выражению darpa*
from filters import *
from svacer import *
cl = SvacerClient(host="http://swarm-mgr:10142",user="admin",password="admin")
f: Filter = Filter(ProjectFilter(id="", name="darpa*"), None, None, None)
param = CreateFilterParam(f)
resp=cl.get(f"/api/public/projects?filters={param}")
print(f"Response: {resp.json()}")Результат может быть следующим
[
{
"project":
{
"id": "019abb61-8cd3-7437-957d-aed0c87e603a",
"name": "darpa-clone",
"time": "2025-11-25T14:18:43.79526Z",
"created_by": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000"
},
"branches":
[
{
"id": "019abb61-83b1-7d80-8d23-ce849387bd6e",
"name": "master",
"time": "2025-11-25T14:18:41.457887Z",
"created_by": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000"
}
]
},
{
"project":
{
"id": "e6abca1b-23a0-4107-9120-4d8d3596030b",
"name": "darpa",
"time": "2020-04-03T04:54:13.754864Z",
"created_by": "importer",
"created_by_id": null
},
"branches":
[
{
"id": "ab179fad-c96a-498d-8407-2a3c82719385",
"name": "master",
"time": "2020-04-03T04:54:13.754864Z",
"created_by": "importer",
"created_by_id": null
}
]
}
]Метод /api/public/projects/{project_id}/branch/{branch_id}/snapshots
С помощью данного метода можно получить список снимков указанной ветки. Пример кода для получения снимков с именем ver. 2.7.0*
from filters import *
from svacer import *
import json
def get_snapshots(pr_id, br_id):
cl = SvacerClient(host="http://swarm-mgr:10142",user="admin",password="admin")
f: Filter = Filter(None,None,SnapshotFilter(id="",name="ver. 2.7.0*"), None)
param = CreateFilterParam(f)
resp=cl.get(f"/api/public/projects/{pr_id}/branch/{br_id}/snapshots?filters={param}")
fmt = json.dumps(resp.json())
print(f"Response: {fmt}")
get_snapshots("e6abca1b-23a0-4107-9120-4d8d3596030b","ab179fad-c96a-498d-8407-2a3c82719385")
Возможный вывод команды:
[
{
"id": "4242b43a-da44-44ca-9b28-770295b98493",
"name": " ver. 2.7.1 200419 05:55",
"time": "2020-04-03T04:56:49.006218Z",
"link": "http://swarm-mgr.home:10142/mode/review/project/e6abca1b-23a0-4107-9120-4d8d3596030b/branch/ab179fad-c96a-498d-8407-2a3c82719385/snapshot/4242b43a-da44-44ca-9b28-770295b98493",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"import_time": "2019-04-20T04:26:52Z",
"details":
{
"branch": "master",
"branchIDHint": "4d1f1413-c638-4a8b-aa4d-d9fccd8df3e9",
"buildObject": "cf43335308de8b7b3ae03735a7f738a6e9246f52",
"dxrIncluded": true,
"host":
{
"hostname": "seroshki",
"user": "sergey"
},
"id": "4242b43a-da44-44ca-9b28-770295b98493",
"importTime": "2019-04-20T04:26:52Z",
"migration-data":
{
"DXR": "ce03cd6d1bd54eac92e227d4184356a90b64b7c1",
"SOURCE_TREE": "0949114563f48d5a2df6e94816b7b1095b6c6540",
"date": "2019-04-20T04:26:52Z",
"description": " ver. 2.7.1 200419 05:55",
"id": "2af625b5faad4083be881135ad1daf6b304e4c99",
"owner": "7a831745d52244db2a4f1692f0c473e61f0f0157",
"parent_id": "0d491fde062e2795a4b38758488a47bf8481d03c",
"sourceData": "cf43335308de8b7b3ae03735a7f738a6e9246f52",
"svres": "2af625b5faad4083be881135ad1daf6b304e4c99.svres.gzip",
"type": "snapshot",
"user": "jenkins"
},
"project": "darpa",
"projectIDHint": "354c9c94-7b57-4427-8ce0-c41f1e59e6c2",
"snapshot": " ver. 2.7.1 200419 05:55",
"sourceIncluded": true
}
},
{
"id": "4f706c3a-fdac-475e-bb0a-8bdd753879ca",
"name": " ver. 2.7.1 130419 07:39",
"time": "2020-04-03T04:58:53.618464Z",
"link": "http://swarm-mgr.home:10142/mode/review/project/e6abca1b-23a0-4107-9120-4d8d3596030b/branch/ab179fad-c96a-498d-8407-2a3c82719385/snapshot/4f706c3a-fdac-475e-bb0a-8bdd753879ca",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"import_time": "2019-04-13T04:33:46Z",
"details":
{
"branch": "master",
"branchIDHint": "c472aab7-d53f-496c-9d3d-069c0901d9bb",
"buildObject": "cf43335308de8b7b3ae03735a7f738a6e9246f52",
"dxrIncluded": false,
"host":
{
"hostname": "seroshki",
"user": "sergey"
},
"id": "4f706c3a-fdac-475e-bb0a-8bdd753879ca",
"importTime": "2019-04-13T04:33:46Z",
"migration-data":
{
"DXR": "ce03cd6d1bd54eac92e227d4184356a90b64b7c1",
"SOURCE_TREE": "0949114563f48d5a2df6e94816b7b1095b6c6540",
"date": "2019-04-13T04:33:46Z",
"description": " ver. 2.7.1 130419 07:39",
"id": "0d491fde062e2795a4b38758488a47bf8481d03c",
"owner": "7a831745d52244db2a4f1692f0c473e61f0f0157",
"parent_id": "edca1583aa41489d37ae9fb2c348ad066ecd3ab3",
"sourceData": "cf43335308de8b7b3ae03735a7f738a6e9246f52",
"svres": "0d491fde062e2795a4b38758488a47bf8481d03c.svres.gzip",
"type": "snapshot",
"user": "jenkins"
},
"project": "darpa",
"projectIDHint": "cf032d99-2efe-4ee0-8db8-ee85ff17b296",
"snapshot": " ver. 2.7.1 130419 07:39",
"sourceIncluded": false
}
}
]Метод /api/public/projects/{project_id}/branch/{branch_id}/snapshots/{snapshot_id}/fullmarkers
Данный метод служит для получения информации о маркерах указанного снимка. Информация о маркере может включать в себя:
- трассу ошибки (параметр traces, возможные значения true,false)
- информацию о чекере (параметр checker_info, возможные значения true,false)
- историю разметки (параметр review_history, возможные значения true,false)
- история комментария (параметр comment_history, возможные значения true,false)
- идентификатор пользовательского фильтра (параметр custom_filter)
- фильтр на параметры маркера
Данный метод может требовать длительного времени выполнения для проектов с большим количеством предупреждений.
Пример кода для получения всего множества информации о маркерах, размеченных со статусом Conf*:
def get_markers (pr_id, br_id, snap_id):
cl = SvacerClient(host="http://swarm-mgr:10142",user="admin",password="admin")
f: Filter = Filter(None, None, None, MarkerFilter(severity="*",
file="*", checker="*", review="Conf*"))
param = CreateFilterParam(f)
resp=cl.get(f"/api/public/projects/{pr_id}/branch/{br_id}/snapshots/{snap_id}/fullmarkers?traces=true&checker_info=true&review_history=true&comment_history=true&filters={param}")
fmt = json.dumps(resp.json())
print(f"Response: {fmt}")
get_markers("e6abca1b-23a0-4107-9120-4d8d3596030b","ab179fad-c96a-498d-8407-2a3c82719385","250a4ff1-bfc8-439a-834d-18b62a545d8d") Возможный вывод:
[
{
"id": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"file": "/mnt/scratch/sources/darpa-source/challenges/Divelogger2/lib/string.cc",
"function": "_ZN6StringaSERKS_",
"line": 179,
"locID": 1006,
"lang": "CXX",
"tool": "SvEng",
"warnClass": "ASSIGN_NO_CHECK_FOR_THIS",
"mtid": "SvEng.LA.4",
"msg": "Method 'operator=' doesn't check its argument with 'this' pointer.",
"details": "d96c832835f414a119ea8c7575a8926378fd7cf6",
"flags": 0,
"traces": [
{
"role": "declaration",
"locations": [
{
"file": "/mnt/scratch/sources/darpa-source/challenges/Divelogger2/lib/string.cc",
"line": 179,
"col": 0,
"spec": false,
"info": "declaration"
}
]
}
],
"checker_severity": "Normal",
"checker_reliability": "High",
"checker_origin": "builtin",
"review": {
"id": "65796",
"status": "Confirmed",
"severity": "Major",
"action": "Fix required",
"createdBy": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000",
"time": "2025-11-25T15:04:25.216816Z",
"createdFrom": "ab877a02-03ac-41ac-8b87-46f7e76791ba"
},
"review_history": [
{
"id": "65796",
"status": "Confirmed",
"severity": "Major",
"action": "Fix required",
"createdBy": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000",
"time": "2025-11-25T15:04:25.216816Z",
"createdFrom": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"createdFromContext": {
"projectID": "e6abca1b-23a0-4107-9120-4d8d3596030b",
"branchID": "ab179fad-c96a-498d-8407-2a3c82719385",
"snapshotID": "250a4ff1-bfc8-439a-834d-18b62a545d8d",
"markerID": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"projectName": "darpa",
"branchName": "master",
"snapshotName": " ver. 2.7.1 300319 07:08",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"create_ts": "2020-04-03T04:56:40.524836Z"
}
},
{
"id": "65795",
"status": "Confirmed",
"severity": "Major",
"action": "Undecided",
"createdBy": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000",
"time": "2025-11-25T15:04:21.683963Z",
"createdFrom": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"createdFromContext": {
"projectID": "e6abca1b-23a0-4107-9120-4d8d3596030b",
"branchID": "ab179fad-c96a-498d-8407-2a3c82719385",
"snapshotID": "250a4ff1-bfc8-439a-834d-18b62a545d8d",
"markerID": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"projectName": "darpa",
"branchName": "master",
"snapshotName": " ver. 2.7.1 300319 07:08",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"create_ts": "2020-04-03T04:56:40.524836Z"
}
},
{
"id": "63495",
"status": "Confirmed",
"severity": "Unspecified",
"action": "Undecided",
"createdBy": "reviewer",
"created_by_id": "077fdd75-b382-4008-97c4-ec6ef8732ccd",
"time": "2022-04-05T11:47:47.026161Z",
"createdFrom": "a94f92f4-4e3e-4071-9f10-aa8e4389dd0a",
"createdFromContext": {
"projectID": "e6abca1b-23a0-4107-9120-4d8d3596030b",
"branchID": "ab179fad-c96a-498d-8407-2a3c82719385",
"snapshotID": "4242b43a-da44-44ca-9b28-770295b98493",
"markerID": "a94f92f4-4e3e-4071-9f10-aa8e4389dd0a",
"projectName": "darpa",
"branchName": "master",
"snapshotName": " ver. 2.7.1 200419 05:55",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"create_ts": "2020-04-03T04:56:49.006218Z"
},
"reviewer_attrs": ["review_master"]
}
],
"comments": [
{
"id": "e3287eb2-9e64-4780-a1c0-22ed9393a226",
"text": "aaaaaaaaa",
"type": "txt",
"ref": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"createdBy": "admin",
"created_by_id": "",
"invariant": "",
"createTs": "2025-11-25T15:04:11.358138Z",
"updateTs": "2025-11-25T15:04:17.220568Z",
"history": [
{
"id": "019abb8b-4244-7931-81f7-a7d1a4512de0",
"comment_id": "e3287eb2-9e64-4780-a1c0-22ed9393a226",
"comment_ref": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"text": "aaaa",
"created_by": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000",
"create_ts": "2025-11-25T15:04:11.358138Z"
}
]
}
],
"invariant": "1pQ3T5bq6AMYEYJqzFsW+Q"
}
]