Metadata-Version: 2.4
Name: savetest-cli
Version: 0.1.3
Summary: CLI for SaveTest: zip Allure results and upload them to SaveTest
License-Expression: MIT
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: click>=8.0
Requires-Dist: requests>=2.28

<p align="center">
  <img src="savetest_cli/pwa-512x512.png" alt="SaveTest" width="128">
</p>

# savetest-cli

CLI-утилита для упаковки Allure-результатов в ZIP и загрузки их в SaveTest.

## Установка

```bash
pip install savetest-cli
```

---

## Быстрый старт

```bash
# 1. Упаковать директорию с результатами в ZIP
savetest zip_report ./AllureReport

# 2. Загрузить в SaveTest и дождаться создания тест-рана
export SAVETEST_HOST=https://savetest.example.com
export SAVETEST_TOKEN=sat_xxxxxxxxxxxxxxxx
export SAVETEST_PROJECT_ID=42
export SAVETEST_BRANCH=main

savetest upload --test-run-name "Smoke $(date +%Y-%m-%d)"
```

---

## Переменные окружения

Все параметры можно задать через переменные окружения — не нужно указывать флаги при каждом вызове.

| Переменная | Обязательна | Описание |
|---|---|---|
| `SAVETEST_HOST` | да | URL вашего SaveTest, например `https://savetest.example.com` |
| `SAVETEST_TOKEN` | да | API-токен (создаётся в настройках профиля SaveTest) |
| `SAVETEST_PROJECT_ID` | да | ID проекта в SaveTest |
| `SAVETEST_BRANCH` | нет | Ветка Git, привязываемая к тест-рану |
| `SAVETEST_TEST_RUN_ID` | нет | ID существующего тест-рана (если не задан — создаётся новый) |
| `SAVETEST_TEST_RUN_NAME` | нет | Имя нового тест-рана |
| `SAVETEST_TEST_RUN_DESCRIPTION` | нет | Описание нового тест-рана |
| `SAVETEST_TEST_RUN_VERSION` | нет | Версия системы |
| `SAVETEST_TEST_RUN_REVISION` | нет | Ревизия / номер сборки |
| `SAVETEST_TEST_RUN_OBJECT` | нет | Объект тестирования |
| `SAVETEST_EPIC_ID` | нет | ID эпика для привязки тест-рана |
| `SAVETEST_EPIC_NAME` | нет | Наименование эпика в проекте (если ID неизвестен) |
| `SAVETEST_CONFIGURATION_ID` | нет | ID конфигурации тест-рана |
| `SAVETEST_CONFIGURATION_NAME` | нет | Наименование конфигурации в проекте |
| `SAVETEST_INCLUDE_ATTACHMENTS` | нет | `true` — включать вложения в ZIP, `false` — исключать (быстрее) |

---

## Команды

### `savetest zip_report <path>`

Упаковывает директорию с Allure-результатами в ZIP-архив.

По умолчанию вложения (картинки, видео, `*-attachment.json`) **не включаются** — архив получается меньше и грузится быстрее. Флаг `--include-attachments` включает их.

```
savetest zip_report [OPTIONS] PATH
```

| Опция | По умолчанию | Описание |
|---|---|---|
| `PATH` | — | Путь к директории с Allure-результатами |
| `--output`, `-o` | `allure-results.zip` | Путь к выходному ZIP-файлу |
| `--include-attachments` | выключено | Включить вложения (картинки, видео, `*-attachment.json`) |

**Примеры:**

```bash
savetest zip_report ./AllureReport

savetest zip_report ./AllureReport --output report.zip

savetest zip_report ./AllureReport --include-attachments
```

---

### `savetest upload`

Загружает ZIP-файл в SaveTest по частям и ждёт завершения импорта. По завершении выводит ссылку на созданный тест-ран.

```
savetest upload [OPTIONS]
```

| Опция | Env-переменная | По умолчанию | Описание |
|---|---|---|---|
| `--host` | `SAVETEST_HOST` | — | URL SaveTest (**обязательно**) |
| `--token`, `-t` | `SAVETEST_TOKEN` | — | API-токен (**обязательно**) |
| `--project-id`, `-p` | `SAVETEST_PROJECT_ID` | — | ID проекта (**обязательно**) |
| `--zip-file`, `-z` | — | `allure-results.zip` | Путь к ZIP-файлу |
| `--branch`, `-b` | `SAVETEST_BRANCH` | — | Ветка Git |
| `--test-run-name` | `SAVETEST_TEST_RUN_NAME` | — | Имя нового тест-рана |
| `--description` | `SAVETEST_TEST_RUN_DESCRIPTION` | — | Описание нового тест-рана |
| `--version` | `SAVETEST_TEST_RUN_VERSION` | — | Версия системы |
| `--revision` | `SAVETEST_TEST_RUN_REVISION` | — | Ревизия / номер сборки |
| `--test-object` | `SAVETEST_TEST_RUN_OBJECT` | — | Объект тестирования |
| `--epic-id` | `SAVETEST_EPIC_ID` | — | ID эпика |
| `--epic-name` | `SAVETEST_EPIC_NAME` | — | Наименование эпика в проекте |
| `--configuration-id` | `SAVETEST_CONFIGURATION_ID` | — | ID конфигурации |
| `--configuration-name` | `SAVETEST_CONFIGURATION_NAME` | — | Наименование конфигурации |
| `--test-run-id` | `SAVETEST_TEST_RUN_ID` | — | ID существующего тест-рана |
| `--include-attachments` | `SAVETEST_INCLUDE_ATTACHMENTS` | выключено | Сообщить серверу, что ZIP содержит вложения |
| `--chunk-size` | — | `50` | Размер чанка при загрузке (МБ) |
| `--wait` / `--no-wait` | — | `--wait` | Ждать завершения импорта |
| `--timeout` | — | `3600` | Таймаут ожидания (сек) |
| `--poll-interval` | — | `1.5` | Интервал опроса статуса (сек) |

`--host`, `--token` и `--project-id` обязательны. Передавайте их через флаги или переменные окружения.

**Примеры:**

```bash
# Через переменные окружения (рекомендуется)
export SAVETEST_HOST=https://savetest.example.com
export SAVETEST_TOKEN=sat_xxxxxxxxxxxxxxxx
export SAVETEST_PROJECT_ID=42

savetest upload --branch main --test-run-name "Regression $(date +%Y-%m-%d)"

# Новый тест-ран с эпиком, конфигурацией и метаданными
savetest upload \
  --branch main \
  --test-run-name "Smoke $(date +%Y-%m-%d)" \
  --epic-name "Release 2.4" \
  --configuration-name "Chrome / Windows" \
  --version "2.4.0" \
  --description "Nightly smoke on staging"

# Загрузить в существующий тест-ран
savetest upload --branch main --test-run-id 17

# Загрузить другой ZIP с вложениями, не ждать импорта
savetest upload --zip-file full-report.zip --include-attachments --no-wait
```

---

## Настройка в Jenkins

Добавьте токен в **Jenkins → Manage Jenkins → Credentials** (тип: Secret text, ID: `savetest-token`).

В `Jenkinsfile` используйте `withCredentials` и `parameters`, чтобы не хранить конфигурацию в коде:

```groovy
pipeline {
    agent any

    parameters {
        string(name: 'SAVETEST_HOST',       defaultValue: '', description: 'URL SaveTest')
        string(name: 'SAVETEST_PROJECT_ID', defaultValue: '', description: 'ID проекта в SaveTest')
        string(name: 'SAVETEST_BRANCH',     defaultValue: '', description: 'Ветка Git')
        string(name: 'SAVETEST_TEST_RUN_ID',defaultValue: '', description: 'ID тест-рана (пусто = создать новый)')
        booleanParam(name: 'INCLUDE_ATTACHMENTS', defaultValue: false, description: 'Включать вложения в ZIP')
    }

    stages {
        // ... ваши стадии запуска тестов ...

        stage('Upload to SaveTest') {
            steps {
                withCredentials([string(credentialsId: 'savetest-token', variable: 'SAVETEST_TOKEN')]) {
                    sh '''
                        pip install savetest-cli

                        savetest zip_report "${WORKSPACE}/AllureReport" \
                            $([ "${INCLUDE_ATTACHMENTS}" = "true" ] && echo "--include-attachments")

                        savetest upload \
                            --host "${SAVETEST_HOST}" \
                            --project-id "${SAVETEST_PROJECT_ID}" \
                            --branch "${SAVETEST_BRANCH}" \
                            --test-run-name "Jenkins ${JOB_NAME} #${BUILD_NUMBER}" \
                            $( [ -n "${SAVETEST_TEST_RUN_ID}" ] && echo "--test-run-id ${SAVETEST_TEST_RUN_ID}" ) \
                            $( [ "${INCLUDE_ATTACHMENTS}" = "true" ] && echo "--include-attachments" )
                    '''
                }
            }
        }
    }
}
```

> `SAVETEST_TOKEN` берётся из Jenkins Credentials и передаётся в окружение через `withCredentials` — в лог и в код сборки он не попадает.

---

## Получение API-токена

1. Войдите в SaveTest.
2. Откройте **Настройки профиля → API-токены**.
3. Создайте новый токен и скопируйте его значение.
4. Добавьте токен в Jenkins Credentials (или экспортируйте локально через `export SAVETEST_TOKEN=...`).
