diff --git a/PLAN.md b/PLAN.md index 5bfc563..16fddb4 100644 --- a/PLAN.md +++ b/PLAN.md @@ -13,7 +13,7 @@ Windows-агент — соседний проект `C:/Users/areso/MusicBridge - Не называть проверки Python сборкой Swift или запуском XCTest. - После этапа обновлять этот файл: реализация, проверки, ограничения, следующий шаг. -## Реализовано в исходниках, требует Xcode-проверки +## Реализовано в исходниках - [x] Проект Xcode, shared scheme, iOS 17+, SwiftUI, без внешних зависимостей. - [x] Модели состояния и команд v1; валидация HTTPS IPv4 домашней сети и QR-строки. @@ -28,8 +28,8 @@ Windows-агент — соседний проект `C:/Users/areso/MusicBridge ## Проверки и следующие шаги -- [ ] Первый успешный xcodebuild + XCTest на macOS. На текущем Windows Swift/Xcode нет. -- [ ] Подключить выбранный пользователем GitHub remote и запустить Actions. +- [x] Первый успешный xcodebuild + XCTest на macOS: 7 тестов, 0 отказов. +- [x] Подключён GitHub remote polskikh13/musicbridgeios; Actions и чтение логов через gh работают. - [ ] Интеграционные тесты TLS: верный/чужой/истёкший сертификат, redirect, WSS. - [ ] Проверить 401 и отзыв устройства, Keychain после переустановки/блокировки. - [ ] Настроить подпись и установку на физический iPhone. @@ -55,3 +55,18 @@ Windows-агент — соседний проект `C:/Users/areso/MusicBridge - `MusicBridgeTests/`: XCTest и пример Windows JSON. - `tools/`: генератор проекта, структурные проверки, выбор симулятора для CI. - `.github/workflows/ios.yml`: CI на macOS. + +## Результаты 2026-09-10 + +- `a761431`: успешный [Actions run 34444563869](https://github.com/polskikh13/musicbridgeios/actions/runs/34444563869), + macos-15, Xcode 16.4, Swift 6.1.2, симулятор iOS 18.5; 7 XCTest прошли. + Артефакты: MusicBridge-simulator и ios-test-results (лог и xcresult), хранение 7 дней. +- Первый CI-прогон не дошёл до компиляции: исправлены регистр UDID и выбор runtime + по версии активного SDK. Две регрессионные Python-проверки прошли локально. +- Структурная проверка Python прошла: генератор детерминирован, ссылки проекта, + состав исходников, Info.plist, схема и JSON согласованы. +- В CI есть предупреждения инструментов о подписанных библиотеках XCTest, + отсутствии AppIntents и Node 20 в checkout/upload-artifact v4; тесты прошли. + Миграция Actions на актуальные версии — отдельное небольшое обновление. +- Следующий шаг: интеграционные проверки TLS/WSS и UI, затем сканер QR/Bonjour. + Физический iPhone, Apple-подпись и управление настоящим ПК ещё не проверены. diff --git a/README.md b/README.md index 56aa234..6bbbd6f 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,11 @@ - WSS-состояние, переподключение с задержкой, остановка сети в фоне и восстановление при возврате. Команды автоматически не повторяются. -**Статус:** исходники первого варианта. Сборка Swift и запуск на устройстве ещё -не подтверждены. Windows не содержит Xcode. Следующий обязательный шаг — первый -прогон GitHub Actions или Xcode на Mac и исправление обнаруженных ошибок. +**Статус:** первый вариант собирается в GitHub Actions на macOS, Xcode 16.4, +Swift 6.1.2. Семь XCTest прошли на симуляторе iOS 18.5; проверка на физическом +iPhone и соединение с Windows-агентом ещё не выполнены. +[Успешный запуск](https://github.com/polskikh13/musicbridgeios/actions/runs/34444563869) +проверяет исходники коммита `a761431`. ## Сборка на Mac @@ -38,12 +40,16 @@ `.github/workflows/ios.yml` собирает приложение и выполняет XCTest на `macos-15` при push в main, pull request или ручном запуске. Сохраняет лог, `.xcresult` и ZIP приложения **для симулятора**, который нельзя установить на физический iPhone. -Apple ID и сертификаты для этой проверки не требуются. Первый облачный запуск пока -не выполнен: нужен GitHub-репозиторий и авторизованный доступ к нему. +Apple ID и сертификаты для этой проверки не требуются. GitHub remote подключён: +`git@github.com:polskikh13/musicbridgeios.git`. GitHub CLI установлен и авторизован; +результаты доступны через `gh run list --repo polskikh13/musicbridgeios` и +`gh run view --repo polskikh13/musicbridgeios --log-failed`. Основной origin: `ssh://git@dev.yukinoki.ru:2222/musicbridge/ios.git`. -Для Actions можно добавить отдельный remote `github`, сохранив основной origin. -Код автоматически не зеркалируется между серверами. +Отдельный remote `github` используется для Actions, основной origin сохранён. +Отправка: `git push origin main` и `git push github main`. +Код автоматически не зеркалируется между серверами. Локальная регрессионная +проверка выбора симулятора: `python tools/test_select_simulator.py`. ## Источники diff --git a/tools/test_select_simulator.py b/tools/test_select_simulator.py new file mode 100644 index 0000000..a00a33b --- /dev/null +++ b/tools/test_select_simulator.py @@ -0,0 +1,36 @@ +import json +import pathlib +import subprocess +import sys +import tempfile +import unittest + + +class SimulatorSelectionTests(unittest.TestCase): + def select(self, devices, sdk): + with tempfile.TemporaryDirectory() as folder: + path = pathlib.Path(folder) / "devices.json" + path.write_text(json.dumps({"devices": devices}), encoding="utf-8") + return subprocess.run([sys.executable, str(pathlib.Path(__file__).with_name("select_simulator.py")), str(path), sdk], + capture_output=True, text=True) + + def test_matches_sdk_and_preserves_id(self): + expected = "DC4CD8B3-4457-4153-9087-A0D7A2F9BFD9" + result = self.select({ + "com.apple.CoreSimulator.SimRuntime.iOS-26-2": [{"name": "iPhone 17", "isAvailable": True, "udid": "E952A9B0-CC78-435C-BF08-06AD47FE1076"}], + "com.apple.CoreSimulator.SimRuntime.iOS-18-5": [{"name": "iPhone 16 Pro", "isAvailable": True, "udid": expected}], + }, "18.5") + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stdout.strip(), "SIMULATOR_ID=" + expected) + + def test_fails_when_sdk_has_no_available_iphone(self): + result = self.select({"com.apple.CoreSimulator.SimRuntime.iOS-18-5": [ + {"name": "iPad", "isAvailable": True, "udid": "DC4CD8B3-4457-4153-9087-A0D7A2F9BFD9"}, + {"name": "iPhone 16", "isAvailable": False, "udid": "E952A9B0-CC78-435C-BF08-06AD47FE1076"}, + ]}, "18.5") + self.assertNotEqual(result.returncode, 0) + self.assertEqual(result.stdout, "") + + +if __name__ == "__main__": + unittest.main()