Тема
Утилита doqactl
doqactl — утилита командной строки: отправляет результаты автотестов в DoQA и возвращает вердикт Quality Gate кодом выхода. Нужна, когда для вашего фреймворка нет адаптера или результаты отправляются из пайплайна без правки проекта тестов.
Где находится
Утилиту не запускают из интерфейса. Её скачивают в пайплайн CI или на локальную машину. Ссылку на неё и готовый шаг пайплайна DoQA показывает здесь: Пространство → «Настройки» → «Подключение CI/CD» → карточка подключения → «Параметры источников» → «Способ подключения» → вкладка «CLI · doqactl».
Экран видят участники пространства с доступом к его настройкам, менять способ подключения может участник с правом управления CI/CD-подключениями. Сама утилита работает не от имени пользователя, а от токена проекта: ролей и прав интерфейса она не проверяет. Где взять токен и данные для пайплайна — Подключение CI/CD.

На скриншоте: 1 — вкладки «Адаптер» и «CLI · doqactl», 2 — «Формат отчёта источника», 3 — «Шаг в пайплайне» с командой doqactl.
Когда выбрать CLI, а не адаптер
| «Адаптер» | «CLI · doqactl» | |
|---|---|---|
| Фреймворк | JUnit 5, JUnit 4, TestNG, pytest — см. Адаптеры | любой |
| Установка | зависимость в проекте тестов | один бинарь, скачивается в шаге пайплайна |
| Что видно в результате | шаги, фикстуры, вложения, параметры | Allure — полная карточка результата; JUnit XML — статус, длительность и текст падения |
| Выборочный запуск | адаптер получает набор тестов от DoQA (у JUnit 4 — не во всех режимах) | Allure — по тест-плану; JUnit XML — только нативным фильтром раннера, его задают в блоке «Выборочный запуск источника» |
Установка
Бинарь называется doqactl; прежнее имя doqa-cli работает как алиас файла: старые пайплайны менять не обязательно. Весь вывод утилиты — по-английски.
bash
curl -fsSL https://doqa.app/downloads/doqactl -o doqactl
chmod +x doqactlСборки есть для Linux (amd64, arm64), macOS (amd64, arm64) и Windows (amd64).
Номеров версий у утилиты нет: doqactl version печатает версию сборки.
Форматы отчётов
| Формат | Что ищет doqactl | Каталоги по умолчанию (watch) |
|---|---|---|
| Allure | сырые файлы *-result.json (+ *-container.json с фикстурами) | allure-results, target/allure-results |
| JUnit XML | файлы *.xml (surefire) | target/surefire-reports, surefire-reports |
Тип определяется по имени файла: оканчивается на -result.json → Allure; на .xml → JUnit. Смешанный набор обоих форматов в одном отчёте — ошибка. Ни того ни другого — тоже ошибка (тексты — в разделе Частые ошибки).
Быстрый старт
В блоке «Способ подключения» откройте вкладку «CLI · doqactl», в поле «Формат отчёта источника» выберите Allure или JUnit XML и нажмите «Сохранить». Пока способ не сохранён, у источника стоит бейдж «Способ не выбран» и DoQA не знает, в каком виде ждать результаты.
Перенесите значения из блока «Данные для пайплайна» в переменные своей CI-системы:
DOQA_URL,DOQA_SPACE_ID,DOQA_TOKEN.Добавьте в пайплайн шаг, который интерфейс печатает в блоке «Шаг в пайплайне»:
bashcurl -fsSL https://doqa.app/downloads/doqactl -o doqactl chmod +x doqactl set +x ./doqactl watch --report-type allure -- <команда запуска тестов>Запустите пайплайн. Результаты уходят в прогон по ходу тестов, ждать конца сборки не нужно.
Вместо переменных значения можно передать флагами --base, --token, --space. Токен — API-токен проекта, которому принадлежит пространство; его создают в админке: «Проекты» → карточка проекта → вкладка «API-токены» (нужны права администратора).
Общая конфигурация
Приоритет источников для одного и того же параметра: флаг > переменная окружения > файл ~/.doqactl.yaml (создаётся командой login). Исключение: явно переданный пустой флаг (--token "") к переменной окружения не откатывается: это защита от джобы с незаполненной переменной, которая иначе ушла бы с чужим токеном раннера.
| Параметр | Флаг | Переменные окружения (по приоритету) |
|---|---|---|
| Базовый URL | --base (у login — --url) | DOQA_API_BASE, DOQA_URL, DOQA_ENDPOINT |
| Токен | --token | DOQA_CI_TOKEN, DOQA_TOKEN |
| Пространство | --space (у gate — --space-id, второе имя всегда есть скрытым алиасом) | DOQA_SPACE_ID, DOQA_SPACE |
| Пайплайн | --pipeline-id | см. таблицу автоопределения |
| Проект в CI | --ci-project-id | DOQA_CI_PROJECT_ID, CI_PROJECT_ID |
| Ветка | --branch | DOQA_BRANCH, CI_COMMIT_REF_NAME, CI_BRANCH, GITHUB_REF_NAME, GIT_BRANCH, BRANCH_NAME |
Коммит (только watch) | --commit | DOQA_COMMIT_SHA, CI_MERGE_REQUEST_SOURCE_BRANCH_SHA, head PR из GITHUB_EVENT_PATH, CI_COMMIT_SHA, GITHUB_SHA, GIT_COMMIT, BUILD_VCS_NUMBER, BUILD_SOURCEVERSION, CIRCLE_SHA1, BITBUCKET_COMMIT, bamboo_planRepository_revision |
| Система-источник | --system | DOQA_SYSTEM (по умолчанию — хост базового URL) |
Ключ CI-подключения (upload, run) | --source-key | DOQA_SOURCE_KEY |
Correlation id (upload, run) | --correlation-id | DOQA_CORRELATION_ID |
Прогон, заведённый DoQA (только watch) | — | DOQA_TEST_RUN_ID (только из окружения) |
Хвостовой /api в базовом URL не удваивается: --base https://doqa.example/api и --base https://doqa.example дают один и тот же адрес. Токен вырезается из сообщений об ошибках и из тела ответа перед печатью, поэтому в лог CI-джобы он не попадает.
--source-key/DOQA_SOURCE_KEY и --correlation-id/DOQA_CORRELATION_ID нужны, когда у пространства несколько CI-подключений: без них результат отклоняется с 409. doqactl сам подставляет DOQA_SOURCE_KEY, если он есть в окружении. Адаптеры JVM и pytest этого пока не делают.
Как определяется CI-система и пайплайн
Значение обязано совпасть с тем, каким DoQA адресует запущенный ею прогон: похожее, но чужое значение прогон не найдёт и заведёт второй.
| CI-система | Откуда берётся идентификатор пайплайна |
|---|---|
| Любая (явно) | DOQA_PIPELINE_ID — проверяется первым и перекрывает всё остальное |
| Jenkins | JOB_NAME + BUILD_NUMBER → {путь job}#{номер}, каждый / в JOB_NAME заменяется на /job/. Пример: JOB_NAME=doqa-e2e/my-job, BUILD_NUMBER=12 → doqa-e2e/job/my-job#12 |
| TeamCity | %teamcity.build.id%: сначала переменная TEAMCITY_BUILD_ID, иначе ключ teamcity.build.id (или build.id) из файла по пути TEAMCITY_BUILD_PROPERTIES_FILE |
| GitLab | CI_PIPELINE_ID |
| GitHub Actions, GitVerse | GITHUB_RUN_ID |
| Azure DevOps | BUILD_BUILDID |
| CircleCI | CIRCLE_PIPELINE_ID |
| Bitbucket | BITBUCKET_PIPELINE_UUID |
| Bamboo | bamboo_buildResultKey |
TEAMCITY_BUILD_ID и BUILD_NUMBER принимаются, только если состоят из одних цифр. В TeamCity нужен именно идентификатор сборки teamcity.build.id, а не её номер BUILD_NUMBER. Там, где провайдер не отдаёт нужное значение, задайте его вручную, например DOQA_PIPELINE_ID: "%teamcity.build.id%".
Команда watch
Прогоняет тестовую команду в CI и отправляет результаты по мере готовности — основная команда для пайплайна.
bash
doqactl watch [флаги] -- <команда запуска тестов>Алиас — stream. Всё после -- — команда тестов; без неё watch только следит за каталогом результатов уже идущего прогона.
Как работает:
- Находит прогон. С заданным
--pipeline-idзапрашивает у DoQA тест-план для прогона, запущенного из DoQA. Если плана нет, создаёт новый прогон. Без--pipeline-idзаводит пустой прогон (локальный сценарий). Готовый прогон можно задать флагом--run, а прогон, заведённый DoQA, подхватывается изDOQA_TEST_RUN_ID. - Если план получен — пишет
testplan.jsonи передаёт его тестовой команде; дляmvn/mvnwсам добавляет-Dallure.testplan.path=<путь>и-Dallure.filter.testplan=true. Файл удаляется после прогона, если не задан--keep-testplan. - Перед запуском чистит каталоги отчётов (кроме
--no-clean). - Запускает тестовую команду и отправляет каждый дописанный результат отдельным запросом сразу, как он перестал меняться. Если есть вложения, запрос уходит multipart’ом. Готовый результат ждёт свои файлы фикстур до
--fixture-waitсекунд. - После выхода команды дособирает оставшиеся результаты ещё до
--wait-resultsсекунд, затем возвращает код.
План не пишется, если он не выразит набор целиком: у части автотестов нет ни селектора, ни Allure ID, либо набор пуст. Тогда прогон идёт полностью, а сужает его нативный фильтр — выражение в переменной DOQA_NATIVE_FILTER, которую подставляет рецепт пайплайна. Сам doqactl её не читает.
Отчёты JUnit XML watch отправляет только в новый прогон: в прогоне, запущенном из DoQA, элементы уже созданы тест-планом и сопоставляются по Allure-идентичности, которой в JUnit XML нет. <!-- TODO verify: что происходит с результатами, если прогон запущен из DoQA, а у источника выбран формат JUnit XML — интерфейс в этом случае всё равно печатает шаг с --report-type junit -->
| Флаг | По умолчанию | Что делает |
|---|---|---|
--results-dir <каталог> | — | корень, внутри которого искать стандартные каталоги отчётов |
--result <каталог> | allure-results, target/allure-results | точный каталог результатов |
--report-type | авто (сначала Allure, потом JUnit) | жёстко задать формат: allure или junit |
--run <id> | — | отправлять по ходу выполнения в существующий прогон по его id, не определяя его |
--commit <sha> | head-коммит из окружения CI | сузить тест-план анализом влияния, если он включён для пространства |
--title | — | название создаваемого прогона |
--ci-type | gitlab | тип провайдера при создании прогона |
--system | хост базового URL | идентификатор системы-источника |
--interval | 2 секунды | интервал опроса каталога результатов |
--idle | 0 (до конца команды или Ctrl-C) | остановиться после N секунд без новых результатов |
--wait-results | 300 секунд | сколько ждать первый результат после выхода команды и досылать зависшую доставку |
--fixture-wait | 10 секунд | сколько готовый результат ждёт свои файлы фикстур во время прогона |
--keep-testplan | выключен | не удалять сгенерированный testplan.json |
--no-clean | выключен | не чистить каталоги отчётов перед запуском |
Плюс общие флаги: --base, --token, --space, --pipeline-id, --branch, --ci-project-id.
bash
./doqactl watch --result target/allure-results -- mvn testКоды возврата: 0 — успех; код упавшей тестовой команды пробрасывается наружу как есть; если команда прошла, а ни одного результата не доставлено — 2.
Команда upload
Загружает уже готовый отчёт (файл, ZIP или каталог) одной командой, для локального запуска или когда отчёт уже собран в CI.
bash
doqactl upload [флаги] <файл|каталог>Ровно один позиционный аргумент: файл (*.xml или *-result.json), ZIP-архив или каталог результатов (каталог архивируется на лету).
| Флаг | По умолчанию | Что делает |
|---|---|---|
--type | auto | формат отчёта: auto, allure или junit |
--title | — | название создаваемого прогона |
--system | хост базового URL | идентификатор системы-источника |
--external-id | — | внешний идентификатор отчёта |
--work-items | — | id тест-кейсов через запятую, которые привязать к отчёту |
--source-key | — | ключ CI-подключения, обязателен при нескольких подключениях у пространства |
--correlation-id | — | идентификатор, по которому DoQA находит свой прогон, пока CI не сообщил идентификатор пайплайна |
Плюс общие флаги: --base, --token, --space, --pipeline-id, --branch, --ci-project-id. Лимит файла — 50 МБ.
bash
./doqactl upload --pipeline-id "$CI_PIPELINE_ID" allure-results/Без --pipeline-id отчёт уйдёт в отдельный прогон
Загрузка отчёта не принимает DOQA_TEST_RUN_ID: отчёт адресуется только идентификатором пайплайна. Без --pipeline-id (или DOQA_PIPELINE_ID) результаты будут отправлены в новый прогон, а прогон, запущенный из DoQA, останется пустым. Команда предупреждает об этом в логе.
Если рядом с результатами лежит файл doqa-reporting.properties (его пишет JVM-адаптер при отказе доставки), upload берёт из него pipelineId, ciRunId, sourceKey, correlationId, branch, но не токен и не адрес сервера. Приоритет — явный флаг, затем переменная DOQA_*, затем данные из файла, затем общие переменные CI.
Коды возврата: 0 — успех, в stdout Report accepted: runId=<id>; 2 — ошибка (файл больше лимита, сервер не вернул runId, сетевая или HTTP-ошибка).
Команда run
Выполняет тестовую команду и после неё загружает готовый отчёт — короткий локальный сценарий. Для CI используйте watch.
bash
doqactl run [флаги] --result <путь> -- <команда тестов>stdout/stderr/stdin тестовой команды проксируются как есть. Отчёт из --result грузится независимо от исхода тестов, тем же путём, что upload; флаги — те же, что у upload, плюс:
| Флаг | По умолчанию | Что делает |
|---|---|---|
--result <путь> | — | путь к отчёту для загрузки после тестов; обязателен |
bash
./doqactl run --result allure-results/ -- pytestКоды возврата: без --result — 2 (run failed: --result is required to upload the report); иначе наружу идёт код тестовой команды. Если тесты упали и загрузка отчёта тоже не удалась — наружу код тестов, а ошибка загрузки печатается отдельной строкой doqactl: upload failed: ….
Команда gate
Возвращает вердикт Quality Gate по пайплайну кодом выхода, чтобы блокировать пайплайн без похода в интерфейс.
bash
doqactl gate [флаги]Позиционных аргументов нет. Нужны токен, положительный целый --space/--space-id и --pipeline-id (без него — pipeline id is required). Статус pending опрашивается раз в секунду до 60 секунд, дальше — timed out waiting for quality gate result.
Дополнительных флагов, кроме общих (--base, --token, --space/--space-id, --pipeline-id, --ci-project-id), у команды нет.
bash
./doqactl gate --pipeline-id "$CI_PIPELINE_ID"Вывод:
text
Quality Gate: failed (blocking=true)
Violated criteria:
- pass_rate: expected 95, actual 92.31
Evaluated metrics:
duration_ms: 812000При отсутствии нарушений или метрик печатается Violated criteria: none / Evaluated metrics: none.
Коды возврата: 0 — гейт не блокирует; 1 — блокирует; 2 — ошибка аргументов, сети, HTTP или разбора ответа (в том числе неизвестный статус в ответе — это не считается успешным прохождением гейта).
Вердикт — про весь прогон, а не про часть, затронутую текущим пайплайном: пайплайн, перезапустивший часть тестов (перезапуск выбранных, перезапуск одного автотеста, авто-повтор), получает passed только тогда, когда успешен весь прогон.
Команда sync-ids
Сопоставляет локальные тесты с идентификаторами автотестов в DoQA и, по флагу, проставляет их в исходники.
bash
doqactl sync-ids [--dir <каталог>] [--lang <язык>] [--update-ids] [--create]Без --update-ids команда ничего не меняет, а печатает расхождения: каким тестам назначены идентификаторы, какие остались без них, какие идентификаторы в DoQA остались без тестов.
| Флаг | По умолчанию | Что делает |
|---|---|---|
--dir | . (текущий каталог) | каталог с исходниками тестов |
--lang | все языки | ограничить языком: py, go, java, ts, js, php, cs |
--update-ids | выключен | вписать выданный id в исходники (идемпотентно, уже помеченные тесты не трогает) |
--create | выключен | разрешить DoQA создать недостающие автотесты и вернуть их id; без флага запрос только читает |
Пропускаемые каталоги: .git, vendor, node_modules, .idea, .vscode, target, bin, obj, dist, build, __pycache__.
bash
./doqactl sync-ids --dir ./src/test --lang java --update-ids--update-ids правит файлы в рабочей директории
Команда дописывает идентификатор прямо в исходный код теста: это изменение рабочего дерева, как любая другая правка файла. Уже помеченные тесты не трогаются: распознаются маркеры @doqa.id(...), @pytest.mark.doqa_id(...), @DoqaId(...), [DoqaId(...)], #[DoqaId(...)], //doqa:…, а также идентификатор в названии теста вида [DOQA-123].
Что вставляется по языкам:
| Язык | Вставляемая строка |
|---|---|
| Python | @doqa.id("DOQA-123") |
| Java | @DoqaId(123) — голое число для числового id, иначе @DoqaId("…") |
| C# | [DoqaId(123)] |
| PHP | #[DoqaId(123)] |
| Go | //doqa:123 |
| TS / JS | // @DoqaId(123) |
Коды возврата: 0 — расхождений нет (или всё прошло с --update-ids); 3 — локальные тесты и id в DoQA разошлись; 4 — не найдено ни одного теста (sync-ids: no tests found in <каталог>).
Команда login
Сохраняет базовый URL, токен и пространство в ~/.doqactl.yaml, чтобы не передавать их флагами при каждом локальном запуске.
bash
doqactl login --base <URL> [--token <токен>] [--space <id>]--url — алиас --base. Файл создаётся с правами 0600 (права сужаются даже у уже существующего файла); путь переопределяется переменной DOQACTL_CONFIG.
Токен можно не светить в argv: он берётся из --token, иначе из $DOQA_TOKEN/$DOQA_CI_TOKEN, иначе из первой строки stdin, если stdin не терминал:
bash
printf '%s' "$DOQA_TOKEN" | doqactl login --base https://doqa.example --space 42Без базового URL или токена — ошибка base URL (--base/--url) and token (--token, $DOQA_TOKEN, or stdin) are required и код 2. Успех — Saved credentials for <URL> to <путь>.
Устаревшая команда report этот конфиг игнорирует (кроме spaceId в старой форме аргументов).
Устаревшая команда report
Отправляет отчёт на URL, указанный первым аргументом, а не на адрес из --base. Оставлена для совместимости со старыми пайплайнами. Для новых используйте upload.
bash
doqactl report <url> <spaceId> <token> <file> [type] [runName]
doqactl report <url> <token> <file> [type]Форма распознаётся по второму аргументу: число — это spaceId, иначе spaceId берётся из --space, DOQA_SPACE_ID или файла ~/.doqactl.yaml. [type] по умолчанию zip (файл или каталог упаковывается в архив); значение allure отправляет файл как есть. [runName] (или флаг --title) — название прогона. Передать его можно только вместе с [type], потому что позиции аргументов фиксированы.
bash
./doqactl report https://example.doqa.app/api/autotests/report 2 abc123 allure-results.zip allureКоды возврата — общие: 0 успех, 2 ошибка аргументов, сети или HTTP.
Прочие команды
| Команда | Что делает |
|---|---|
version | печатает версию сборки |
completion | скрипт автодополнения оболочки |
help | справка по команде; вызов doqactl без подкоманды печатает то же |
Коды возврата (сводно)
| Код | Значение |
|---|---|
0 | успех |
1 | блокирующий вердикт Quality Gate (gate) |
2 | ошибка аргументов, сети, HTTP или разбора ответа |
3 | sync-ids: локальные тесты и id в DoQA разошлись |
4 | sync-ids: не найдено ни одного теста |
| код тестовой команды | watch / run: пробрасывается код возврата обёрнутой команды тестов |
Частые ошибки
| Сообщение | Причина | Действие |
|---|---|---|
Invalid token / «Недействительный токен.» (401) | токен не передан или не найден | проверить --token/DOQA_TOKEN |
Token is not allowed for this space / «Токен не имеет доступа к этому спейсу.» (403) | токен принадлежит другому проекту, чем пространство | использовать токен проекта, которому принадлежит это пространство |
Token is invalid (403, error_token) | токен не прошёл проверку при загрузке отчёта | тот же токен, что и остальные запросы, — токен проекта |
file_too_large — «Максимальный размер файла — 50 МБ» (422) | файл отчёта больше лимита | сузить отчёт или разбить на несколько загрузок |
upload payload exceeds the 50 MB limit | то же самое при upload/run | то же самое |
invalid_space_id — «spaceId must be an integer» (422) | --space не число | проверить значение --space/DOQA_SPACE_ID |
report contains both Allure results and XML files; set --type explicitly | в отчёте одновременно *-result.json и *.xml | явно задать --report-type/--type |
could not detect report type; expected *-result.json or *.xml | ни Allure-, ни JUnit-файлов не найдено | проверить путь и содержимое каталога результатов |
doqactl: warning: no pipeline id resolved; the report will go to a separate run instead of run <id> started by DoQA … | нет --pipeline-id/DOQA_PIPELINE_ID при upload | задать --pipeline-id тем значением, которое CI-провайдер сообщает DoQA |
attachment … not found | файл вложения результата не найден или превышен лимит вложений одного результата (100 МБ, только у watch) | проверить путь к вложению; результат уйдёт без него с пометкой «Вложения не приняты» |
X of Y Allure result(s) were not delivered to run Z: … | часть результатов не доставлена после завершения команды | код возврата 2; смотреть перечисленные причины в сообщении |
run failed: --result is required to upload the report | не передан --result у команды run | добавить --result <путь> |
pipeline id is required (gate) | не передан --pipeline-id | добавить --pipeline-id/DOQA_PIPELINE_ID |
timed out waiting for quality gate result | статус гейта остаётся pending дольше 60 секунд | проверить, что результаты пайплайна уже доставлены в DoQA |
sync-ids: no tests found in <каталог> | --dir указывает не туда или тесты не распознаны | проверить путь и --lang |
base URL (--base/--url) and token (--token, $DOQA_TOKEN, or stdin) are required (login) | не передан URL или токен | добавить --base и --token (или переменные/stdin) |
Особенности
- Запросы за данными и пофайловые отправки результатов повторяются при сетевой ошибке и ошибке сервера. Создание прогона и загрузка отчёта при сетевой ошибке не повторяются, чтобы не завести второй прогон.
- Сбой отправки одного файла не останавливает остальные; результат, отклонённый DoQA ответом 4xx (
rejected by DoQA), повторно не отправляется. - Фикстура (например, общий teardown класса), записанная позже отправки её результата, к уже отправленному результату не добавляется: такие данные видны только при загрузке готового отчёта целиком (
upload).
Смотрите также
- Отправка результатов — как выбрать между адаптером, CLI и загрузкой отчёта через интерфейс
- Запуск автотестов из DoQA — как DoQA передаёт прогон и тест-план в пайплайн
- Autotest API — прямые HTTP-запросы вместо утилиты, для своего адаптера