Last active
December 16, 2025 13:28
-
-
Save androiddevcoding/d7b6158f4d6e0c09680bb6240f3ccc72 to your computer and use it in GitHub Desktop.
Скрипт для запуска Maestro UI-тестов на Android эмуляторе.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| IFS=$'\n\t' | |
| # ============================================================================= | |
| # Скрипт для запуска Maestro UI-тестов на Android эмуляторе. | |
| # Может использоваться в pre-push хуке или запускаться вручную. | |
| # | |
| # Использование: | |
| # ${0##*/} [--sdk SDK_PATH] [--maestro MAESTRO_PATH] [--avd AVD_NAME] \ | |
| # [--flows TESTS_DIR] [--gradle-task TASK] [--apk APK_PATH] | |
| # | |
| # Переменные окружения (переопределяют значения по умолчанию): | |
| # ANDROID_SDK_ROOT/ANDROID_HOME, MAESTRO_BIN, AVD_NAME, MAESTRO_DIR, | |
| # GRADLE_TASK, APP_APK | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Глобальные константы и значения по умолчанию | |
| # ----------------------------------------------------------------------------- | |
| readonly AVD_NAME_DEFAULT="Pixel_6_Pro" | |
| readonly MAESTRO_DIR_DEFAULT="testMaestro/mock" | |
| readonly BOOT_TIMEOUT_DEFAULT=240 | |
| readonly GRADLE_TASK_DEFAULT="assembleRustoreMockDebug" | |
| readonly APP_APK_DEFAULT="app/build/outputs/apk/rustoreMock/debug/app-rustore-mock-debug.apk" | |
| # Путь к scrcpy (установлен через winget) | |
| readonly SCRCPY_DIR="/c/Users/codin/AppData/Local/Microsoft/WinGet/Packages/Genymobile.scrcpy_Microsoft.Winget.Source_8wekyb3d8bbwe/scrcpy-win64-v3.3.3" | |
| # ----------------------------------------------------------------------------- | |
| # Глобальные переменные (инициализируются позже) | |
| # ----------------------------------------------------------------------------- | |
| ROOT="" | |
| LOG_DIR="" | |
| LOG_FILE="" | |
| TS="" | |
| SCRCPY_AVAILABLE=0 | |
| SCRCPY_PID="" | |
| SCRCPY_FILE="" | |
| SCRCPY_RECORD_DIR="" | |
| UNAME_OUT="" | |
| SDK_ROOT="" | |
| ADB="" | |
| EMULATOR="" | |
| MAESTRO_BIN="" | |
| AVD_NAME="" | |
| MAESTRO_DIR="" | |
| BOOT_TIMEOUT="" | |
| GRADLE_TASK="" | |
| APP_APK="" | |
| # Метка для именования папок отчётов (будет заменена на имя AVD после его определения) | |
| RUN_LABEL="" | |
| # ============================================================================= | |
| # ФУНКЦИИ ЛОГИРОВАНИЯ | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Вывод сообщения с меткой в консоль и лог-файл | |
| # Параметры: сообщение для вывода | |
| # ----------------------------------------------------------------------------- | |
| log() { | |
| local label="${RUN_LABEL:-maestro}" | |
| echo "[${label}] $*" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Инициализация системы логирования | |
| # Определяет корневую директорию, создаёт папку для логов, настраивает tee | |
| # ----------------------------------------------------------------------------- | |
| init_logging() { | |
| ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" | |
| TS="$(date +"%Y%m%d-%H%M%S")" | |
| log "Запуск: $(date)" | |
| log "Репозиторий: $ROOT" | |
| } | |
| # ============================================================================= | |
| # ФУНКЦИИ ИНИЦИАЛИЗАЦИИ SCRCPY (ЗАПИСЬ ЭКРАНА) | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Проверка доступности scrcpy и добавление в PATH при наличии | |
| # ----------------------------------------------------------------------------- | |
| init_scrcpy() { | |
| if [[ -x "$SCRCPY_DIR/scrcpy.exe" ]]; then | |
| export PATH="$SCRCPY_DIR:$PATH" | |
| SCRCPY_AVAILABLE=1 | |
| log "scrcpy включён: $SCRCPY_DIR" | |
| else | |
| log "scrcpy не найден в $SCRCPY_DIR - запись видео отключена" | |
| fi | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Запуск записи экрана через scrcpy | |
| # Вызывается перед установкой APK | |
| # ----------------------------------------------------------------------------- | |
| start_scrcpy_recording() { | |
| if [[ "$SCRCPY_AVAILABLE" -eq 1 && -z "$SCRCPY_PID" ]]; then | |
| mkdir -p "$SCRCPY_RECORD_DIR" | |
| SCRCPY_FILE="$SCRCPY_RECORD_DIR/${RUN_LABEL}-${TS}.mp4" | |
| log "Запуск записи scrcpy: $SCRCPY_FILE" | |
| scrcpy --no-window --no-audio --record="$SCRCPY_FILE" & | |
| SCRCPY_PID=$! | |
| fi | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Корректная остановка записи scrcpy для получения валидного MP4-файла | |
| # Отправляет SIGINT, ожидает завершения, проверяет файл | |
| # ----------------------------------------------------------------------------- | |
| stop_scrcpy_recording() { | |
| if [[ -z "$SCRCPY_PID" ]]; then | |
| return 0 | |
| fi | |
| log "Остановка записи scrcpy (PID=$SCRCPY_PID)" | |
| # Отправляем SIGINT (эквивалент Ctrl+C) для корректного завершения | |
| kill -INT "$SCRCPY_PID" 2>/dev/null || true | |
| # Ожидаем до 10 секунд корректного завершения | |
| local waited=0 | |
| while kill -0 "$SCRCPY_PID" 2>/dev/null; do | |
| sleep 1 | |
| waited=$((waited + 1)) | |
| if [[ $waited -ge 10 ]]; then | |
| log "scrcpy не завершился вовремя; отправляем SIGTERM" | |
| kill -TERM "$SCRCPY_PID" 2>/dev/null || true | |
| break | |
| fi | |
| done | |
| # Финальное ожидание процесса | |
| wait "$SCRCPY_PID" 2>/dev/null || true | |
| SCRCPY_PID="" | |
| # Пауза для записи и закрытия контейнера | |
| sleep 1 | |
| # Проверяем результат записи | |
| if [[ -n "$SCRCPY_FILE" && -f "$SCRCPY_FILE" ]]; then | |
| local size | |
| size=$(stat -c %s "$SCRCPY_FILE" 2>/dev/null || stat -f %z "$SCRCPY_FILE" 2>/dev/null || echo 0) | |
| if [[ "$size" -gt 0 ]]; then | |
| log "Запись scrcpy завершена: $SCRCPY_FILE (${size} байт)" | |
| else | |
| log "Предупреждение: файл записи пуст или повреждён: $SCRCPY_FILE" | |
| fi | |
| else | |
| log "Предупреждение: файл записи не найден: $SCRCPY_FILE" | |
| fi | |
| } | |
| # ============================================================================= | |
| # ФУНКЦИИ ОБРАБОТКИ КОНФИГУРАЦИИ | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Применение значений по умолчанию из переменных окружения | |
| # ----------------------------------------------------------------------------- | |
| apply_defaults() { | |
| AVD_NAME="${AVD_NAME:-$AVD_NAME_DEFAULT}" | |
| MAESTRO_DIR="${MAESTRO_DIR:-$MAESTRO_DIR_DEFAULT}" | |
| BOOT_TIMEOUT="${BOOT_TIMEOUT:-$BOOT_TIMEOUT_DEFAULT}" | |
| GRADLE_TASK="${GRADLE_TASK:-$GRADLE_TASK_DEFAULT}" | |
| APP_APK="${APP_APK:-$APP_APK_DEFAULT}" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Настройка метки запуска и путей для логов/отчётов/записей | |
| # Вызывается после определения AVD_NAME | |
| # ----------------------------------------------------------------------------- | |
| setup_run_label() { | |
| # Метка формируется из имени AVD | |
| RUN_LABEL="$AVD_NAME" | |
| # Все логи, отчёты и записи хранятся в maestro-report | |
| LOG_DIR="$ROOT/maestro-report/${RUN_LABEL}-${TS}" | |
| mkdir -p "$LOG_DIR" | |
| LOG_FILE="$LOG_DIR/run.log" | |
| # Папка для записи видео (внутри папки отчёта) | |
| SCRCPY_RECORD_DIR="$LOG_DIR" | |
| # Перенаправляем stdout и stderr в консоль и лог-файл одновременно | |
| exec > >(tee -a "$LOG_FILE") 2>&1 | |
| log "Метка запуска: $RUN_LABEL" | |
| log "Папка отчёта: $LOG_DIR" | |
| log "Лог-файл: $LOG_FILE" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Разбор аргументов командной строки | |
| # Параметры: все аргументы скрипта ($@) | |
| # ----------------------------------------------------------------------------- | |
| parse_arguments() { | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| --sdk) | |
| if [[ $# -lt 2 ]]; then | |
| log "Ошибка: --sdk требует путь" | |
| exit 1 | |
| fi | |
| ANDROID_SDK_ROOT="$2" | |
| shift 2 | |
| ;; | |
| --maestro) | |
| if [[ $# -lt 2 ]]; then | |
| log "Ошибка: --maestro требует путь" | |
| exit 1 | |
| fi | |
| MAESTRO_BIN="$2" | |
| shift 2 | |
| ;; | |
| --avd) | |
| if [[ $# -lt 2 ]]; then | |
| log "Ошибка: --avd требует имя" | |
| exit 1 | |
| fi | |
| AVD_NAME="$2" | |
| shift 2 | |
| ;; | |
| --flows|--maestro-dir) | |
| if [[ $# -lt 2 ]]; then | |
| log "Ошибка: --flows требует директорию" | |
| exit 1 | |
| fi | |
| MAESTRO_DIR="$2" | |
| shift 2 | |
| ;; | |
| --gradle-task|--task) | |
| if [[ $# -lt 2 ]]; then | |
| log "Ошибка: --gradle-task требует имя задачи" | |
| exit 1 | |
| fi | |
| GRADLE_TASK="$2" | |
| shift 2 | |
| ;; | |
| --apk) | |
| if [[ $# -lt 2 ]]; then | |
| log "Ошибка: --apk требует путь к файлу" | |
| exit 1 | |
| fi | |
| APP_APK="$2" | |
| shift 2 | |
| ;; | |
| --help|-h) | |
| show_help | |
| exit 0 | |
| ;; | |
| *) | |
| log "Ошибка: Неизвестный параметр $1" | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Вывод справки по использованию скрипта | |
| # ----------------------------------------------------------------------------- | |
| show_help() { | |
| cat << EOF | |
| Использование: ${0##*/} [ПАРАМЕТРЫ] | |
| Параметры: | |
| --sdk SDK_PATH Путь к Android SDK | |
| --maestro MAESTRO_PATH Путь к исполняемому файлу Maestro | |
| --avd AVD_NAME Имя Android Virtual Device | |
| --flows DIR Директория с Maestro тестами | |
| --gradle-task TASK Gradle задача для сборки APK | |
| --apk APK_PATH Путь к APK файлу | |
| --help, -h Показать эту справку | |
| EOF | |
| } | |
| # ============================================================================= | |
| # ФУНКЦИИ ПРЕОБРАЗОВАНИЯ ПУТЕЙ | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Преобразование Windows-пути в Unix-формат (для Git Bash) | |
| # Параметры: путь для преобразования | |
| # Возвращает: преобразованный путь через stdout | |
| # ----------------------------------------------------------------------------- | |
| convert_windows_path_to_unix() { | |
| local path="$1" | |
| if [[ "$path" =~ ^[A-Za-z]:\\ ]] || [[ "$path" =~ ^[A-Za-z]:/ ]]; then | |
| if command -v cygpath >/dev/null 2>&1; then | |
| cygpath "$path" | |
| else | |
| local drive_letter | |
| drive_letter="$(echo "$path" | cut -c1 | tr '[:upper:]' '[:lower:]')" | |
| local rest_path="${path:2}" | |
| rest_path="${rest_path//\\/\/}" | |
| echo "/$drive_letter/$rest_path" | |
| fi | |
| else | |
| echo "$path" | |
| fi | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Нормализация всех путей из конфигурации | |
| # Преобразует Windows-пути в Unix-формат при необходимости | |
| # ----------------------------------------------------------------------------- | |
| normalize_paths() { | |
| MAESTRO_DIR="$(convert_windows_path_to_unix "$MAESTRO_DIR")" | |
| APP_APK="$(convert_windows_path_to_unix "$APP_APK")" | |
| # Определяем тип ОС | |
| UNAME_OUT="$(uname -s || true)" | |
| } | |
| # ============================================================================= | |
| # ФУНКЦИИ НАСТРОЙКИ ANDROID SDK | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Поиск и настройка Android SDK | |
| # Ищет SDK в стандартных местах, если не задан явно | |
| # ----------------------------------------------------------------------------- | |
| setup_android_sdk() { | |
| SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" | |
| if [[ -z "$SDK_ROOT" ]]; then | |
| log "ANDROID_SDK_ROOT и ANDROID_HOME не заданы, ищем SDK..." | |
| case "$UNAME_OUT" in | |
| Darwin*) | |
| SDK_ROOT="$HOME/Library/Android/sdk" | |
| ;; | |
| Linux*) | |
| SDK_ROOT="$HOME/Android/Sdk" | |
| ;; | |
| MINGW*|MSYS*|CYGWIN*) | |
| SDK_ROOT="$HOME/AppData/Local/Android/Sdk" | |
| ;; | |
| *) | |
| SDK_ROOT="" | |
| ;; | |
| esac | |
| if [[ -n "$SDK_ROOT" && -d "$SDK_ROOT" ]]; then | |
| log "Используем путь SDK по умолчанию: $SDK_ROOT" | |
| else | |
| log "Android SDK не найден. Установите ANDROID_SDK_ROOT." | |
| exit 1 | |
| fi | |
| fi | |
| # Преобразуем Windows-путь в Unix-формат | |
| SDK_ROOT="$(convert_windows_path_to_unix "$SDK_ROOT")" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Настройка путей к adb и эмулятору | |
| # Добавляет расширение .exe для Windows при необходимости | |
| # ----------------------------------------------------------------------------- | |
| setup_android_tools() { | |
| ADB="${SDK_ROOT}/platform-tools/adb" | |
| EMULATOR="${SDK_ROOT}/emulator/emulator" | |
| # Добавляем .exe для Windows | |
| case "$UNAME_OUT" in | |
| MINGW*|MSYS*|CYGWIN*) | |
| if [[ -f "${ADB}.exe" ]]; then ADB="${ADB}.exe"; fi | |
| if [[ -f "${EMULATOR}.exe" ]]; then EMULATOR="${EMULATOR}.exe"; fi | |
| ;; | |
| esac | |
| # Проверяем доступность adb | |
| if [[ ! -x "$ADB" && ! -f "$ADB" ]]; then | |
| if command -v adb >/dev/null 2>&1; then | |
| ADB="adb" | |
| else | |
| log "adb не найден." | |
| exit 1 | |
| fi | |
| fi | |
| # Проверяем доступность эмулятора | |
| if [[ ! -x "$EMULATOR" && ! -f "$EMULATOR" ]]; then | |
| if command -v emulator >/dev/null 2>&1; then | |
| EMULATOR="emulator" | |
| else | |
| log "emulator не найден." | |
| exit 1 | |
| fi | |
| fi | |
| } | |
| # ============================================================================= | |
| # ФУНКЦИИ НАСТРОЙКИ MAESTRO CLI | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Поиск и настройка Maestro CLI | |
| # Проверяет наличие Maestro в PATH или по указанному пути | |
| # ----------------------------------------------------------------------------- | |
| setup_maestro_cli() { | |
| # Преобразуем путь Maestro, если задан | |
| if [[ -n "${MAESTRO_BIN:-}" ]]; then | |
| MAESTRO_BIN="$(convert_windows_path_to_unix "$MAESTRO_BIN")" | |
| fi | |
| if [[ -z "${MAESTRO_BIN:-}" ]]; then | |
| # Ищем Maestro в PATH | |
| if command -v maestro >/dev/null 2>&1; then | |
| MAESTRO_BIN="maestro" | |
| elif command -v maestro.bat >/dev/null 2>&1; then | |
| MAESTRO_BIN="maestro.bat" | |
| else | |
| log "Maestro CLI не найден. Установите Maestro или задайте MAESTRO_BIN." | |
| exit 1 | |
| fi | |
| else | |
| # Проверяем указанный путь | |
| if [[ "$MAESTRO_BIN" == *"/"* ]]; then | |
| if [[ ! -f "$MAESTRO_BIN" ]]; then | |
| log "Maestro не найден по пути: $MAESTRO_BIN" | |
| exit 1 | |
| fi | |
| else | |
| if ! command -v "$MAESTRO_BIN" >/dev/null 2>&1; then | |
| log "Maestro '$MAESTRO_BIN' не найден в PATH." | |
| exit 1 | |
| fi | |
| fi | |
| fi | |
| } | |
| # ============================================================================= | |
| # ФУНКЦИИ УПРАВЛЕНИЯ ЭМУЛЯТОРОМ | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Проверка, запущен ли уже эмулятор | |
| # Возвращает: 0 если эмулятор запущен, 1 если нет | |
| # ----------------------------------------------------------------------------- | |
| is_emulator_running() { | |
| # Используем subshell и || true для защиты от set -e | |
| if "$ADB" devices 2>/dev/null | tail -n +2 | grep -q "^emulator-"; then | |
| return 0 | |
| else | |
| return 1 | |
| fi | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Запуск эмулятора AVD в фоновом режиме | |
| # ----------------------------------------------------------------------------- | |
| start_emulator() { | |
| log "Запуск эмулятора: $AVD_NAME" | |
| "$EMULATOR" -avd "$AVD_NAME" -netdelay none -netspeed full >/dev/null 2>&1 & | |
| sleep 5 | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Ожидание полной загрузки эмулятора | |
| # Проверяет sys.boot_completed и init.svc.bootanim | |
| # Завершается с ошибкой при превышении таймаута | |
| # ----------------------------------------------------------------------------- | |
| wait_for_boot() { | |
| log "Ожидание загрузки эмулятора (таймаут ${BOOT_TIMEOUT} сек)..." | |
| local elapsed=0 | |
| local interval=5 | |
| while [[ $elapsed -lt $BOOT_TIMEOUT ]]; do | |
| # Используем || true чтобы избежать выхода из-за set -e когда эмулятор ещё не появился | |
| if "$ADB" devices 2>/dev/null | tail -n +2 | grep -q "^emulator-"; then | |
| local boot_completed="" | |
| local boot_anim="" | |
| # Получаем статус загрузки с защитой от ошибок | |
| boot_completed="$("$ADB" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)" | |
| boot_anim="$("$ADB" shell getprop init.svc.bootanim 2>/dev/null | tr -d '\r' || true)" | |
| if [[ "$boot_completed" == "1" || "$boot_anim" == "stopped" ]]; then | |
| log "Эмулятор загружен." | |
| return 0 | |
| fi | |
| log "Ожидание... (boot_completed=$boot_completed, boot_anim=$boot_anim)" | |
| else | |
| log "Ожидание появления эмулятора в списке устройств..." | |
| fi | |
| sleep "$interval" | |
| elapsed=$((elapsed + interval)) | |
| done | |
| log "Эмулятор не загрузился за ${BOOT_TIMEOUT} секунд." | |
| exit 1 | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Управление запуском эмулятора | |
| # Запускает новый эмулятор, если он ещё не запущен | |
| # ----------------------------------------------------------------------------- | |
| ensure_emulator_running() { | |
| if is_emulator_running; then | |
| log "Эмулятор уже запущен." | |
| else | |
| log "Запуск нового эмулятора..." | |
| start_emulator | |
| fi | |
| wait_for_boot | |
| } | |
| # ============================================================================= | |
| # ФУНКЦИИ СБОРКИ И ТЕСТИРОВАНИЯ | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Сборка APK через Gradle | |
| # Выполняет указанную Gradle-задачу и проверяет наличие результата | |
| # ----------------------------------------------------------------------------- | |
| build_apk() { | |
| log "Сборка APK с помощью Gradle: $GRADLE_TASK" | |
| (cd "$ROOT" && ./gradlew "$GRADLE_TASK") | |
| local apk_path="$APP_APK" | |
| if [[ "$apk_path" != /* ]]; then | |
| apk_path="$ROOT/$apk_path" | |
| fi | |
| if [[ ! -f "$apk_path" ]]; then | |
| log "APK не найден: $apk_path" | |
| exit 1 | |
| fi | |
| log "APK готов: $apk_path" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Установка APK на эмулятор | |
| # Параметры: путь к APK | |
| # ----------------------------------------------------------------------------- | |
| install_apk() { | |
| local apk_path="$1" | |
| log "Установка APK через adb : $apk_path" | |
| "$ADB" install -r "$apk_path" || { | |
| log "Ошибка установки APK через adb" | |
| stop_scrcpy_recording | |
| exit 1 | |
| } | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Запуск Maestro тестов | |
| # Создаёт отчёты в HTML формате с отладочной информацией | |
| # ----------------------------------------------------------------------------- | |
| run_maestro_tests() { | |
| local flows_path="$1" | |
| local report_dir="$ROOT/maestro-report/${RUN_LABEL}-${TS}" | |
| mkdir -p "$report_dir" | |
| local debug_dir="$report_dir/debug" | |
| mkdir -p "$debug_dir" | |
| log "Запуск Maestro тестов..." | |
| "$MAESTRO_BIN" test \ | |
| --debug-output="$debug_dir" \ | |
| --format=HTML \ | |
| --output="$report_dir/report.html" \ | |
| "$flows_path" \ | |
| 2>&1 | tee "$report_dir/maestro-output.log" || { | |
| log "=====================================" | |
| log "Maestro тесты ПРОВАЛЕНЫ!" | |
| log "Отчёт сохранён: $report_dir" | |
| log "HTML отчёт: $report_dir/report.html" | |
| log "Отладочный вывод: $debug_dir" | |
| stop_scrcpy_recording | |
| log "=====================================" | |
| exit 1 | |
| } | |
| # Останавливаем запись после успешного прогона | |
| stop_scrcpy_recording | |
| sleep 2 | |
| log "Maestro тесты пройдены!" | |
| log "Отчёт сохранён: $report_dir" | |
| log "HTML отчёт: $report_dir/report.html" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Запуск полного цикла Maestro тестирования | |
| # Устанавливает APK, запускает запись экрана и выполняет тесты | |
| # ----------------------------------------------------------------------------- | |
| run_maestro() { | |
| local flows_path="$MAESTRO_DIR" | |
| if [[ "$flows_path" != /* ]]; then | |
| flows_path="$ROOT/$flows_path" | |
| fi | |
| local apk_path="$APP_APK" | |
| if [[ "$apk_path" != /* ]]; then | |
| apk_path="$ROOT/$apk_path" | |
| fi | |
| if [[ ! -d "$flows_path" ]]; then | |
| log "Директория Maestro не найдена: $flows_path" | |
| exit 1 | |
| fi | |
| log "Запуск Maestro flows из: $flows_path" | |
| # Запуск записи экрана перед установкой APK | |
| start_scrcpy_recording | |
| # Установка APK | |
| install_apk "$apk_path" | |
| # Запуск тестов | |
| run_maestro_tests "$flows_path" | |
| } | |
| # ============================================================================= | |
| # ФУНКЦИИ ВЫВОДА ИНФОРМАЦИИ | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Вывод текущей конфигурации | |
| # Отображает все используемые пути и настройки | |
| # ----------------------------------------------------------------------------- | |
| print_configuration() { | |
| log "SDK_ROOT: ${SDK_ROOT:-<не задан>}" | |
| log "Используемый adb: $ADB" | |
| log "Используемый emulator: $EMULATOR" | |
| log "Используемый Maestro: $MAESTRO_BIN" | |
| log "AVD_NAME: $AVD_NAME" | |
| log "MAESTRO_DIR: $MAESTRO_DIR" | |
| log "GRADLE_TASK: $GRADLE_TASK" | |
| log "APP_APK: $APP_APK" | |
| } | |
| # ============================================================================= | |
| # ГЛАВНАЯ ФУНКЦИЯ | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Главная точка входа скрипта | |
| # Координирует весь процесс тестирования | |
| # Параметры: все аргументы командной строки ($@) | |
| # ----------------------------------------------------------------------------- | |
| main() { | |
| # 1. Инициализация логирования | |
| init_logging | |
| # 2. Инициализация scrcpy | |
| init_scrcpy | |
| # 3. Применение значений по умолчанию | |
| apply_defaults | |
| # 4. Разбор аргументов командной строки | |
| parse_arguments "$@" | |
| # 5. Настройка метки запуска и путей (после определения AVD_NAME) | |
| setup_run_label | |
| # 6. Нормализация путей | |
| normalize_paths | |
| # 7. Настройка Android SDK и инструментов | |
| setup_android_sdk | |
| setup_android_tools | |
| # 8. Настройка Maestro CLI | |
| setup_maestro_cli | |
| # 9. Вывод конфигурации | |
| print_configuration | |
| # 10. Запуск эмулятора | |
| ensure_emulator_running | |
| # 11. Сборка APK | |
| build_apk | |
| # 12. Запуск Maestro тестов | |
| run_maestro | |
| log "Maestro тесты успешно пройдены." | |
| exit 0 | |
| } | |
| # ============================================================================= | |
| # ТОЧКА ВХОДА | |
| # ============================================================================= | |
| # Запуск главной функции с передачей всех аргументов | |
| main "$@" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| PROJECT_ROOT="$(git rev-parse --show-toplevel)" | |
| echo "[pre-push] Project root: $PROJECT_ROOT" | |
| SCRIPT="$PROJECT_ROOT/scripts/maestro_emulator_check.sh" | |
| if [ ! -f "$SCRIPT" ]; then | |
| echo "[pre-push] ERROR: Script not found: $SCRIPT" | |
| exit 1 | |
| fi | |
| echo "[pre-push] Running Maestro script..." | |
| sh "$SCRIPT" | |
| STATUS=$? | |
| if [ $STATUS -ne 0 ]; then | |
| echo "======================================" | |
| echo "[pre-push] ❌ Push blocked: Maestro tests FAILED" | |
| echo "======================================" | |
| exit 1 | |
| fi | |
| echo "======================================" | |
| echo "[pre-push] ✅ Maestro tests passed. Push allowed." | |
| echo "======================================" | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment