Свой CI/CD для Unity

    image

    Сейчас я расскажу, как выглядит процесс разработки на Unity в маленькой gamedev компании и как мы его улучшаем и автоматизируем. Всё-таки 2020 год на дворе, хватит уже мышкой водить…

    Про мышку, это не такая уж и шутка. До недавнего времени, процесс тестирования и разработки игр у нас выглядел примерно так:

    Android


    1. Разработчики пишут код
    2. Собирается версия для Android
    3. Загружается в общую папку на Google Диск
    4. Тестировщик скачивает последний билд
    5. Тестирует и закидывает задачи в Redmine
    6. Goto: шаг 1

    С версией для iOS немного сложнее:

    iOS


    1. Разработчики пишут код
    2. Собирается Xcode проект
    3. Postbuild скрипт добавляет в него локализации, SDK и прочее
    4. Компилируется проект
    5. Архивируется
    6. Экспортируется в IPA файл (всё это делается не очень быстро, хаха)
    7. После этого можно залить IPA в общую папку на Google Диск
    8. Или загрузить в TestFlight, где можно прождать пару дней
    9. Тестировщик скачивает последний IPA
    10. Подключает девайс, устанавливает приложение
    11. Тестирует и закидывает задачи в Redmine
    12. Goto: шаг 1

    Вот такая печаль. И если для Android, процесс ещё как-то приемлем (нет), то для iOS – всё очень долго, неудобно и неправильно. Кроме того, большинство операций делается вручную разработчиком (вот тут про мышку) и время которое может быть затрачено на разработку, уходит на ожидание компиляции, экспорта Xcode проекта и прочее. Это ещё надо учесть, что все находятся в одном офисе, т.е. можно подойти спросить/сказать что-то перед запуском всего этого адского процесса.

    Но, в общем, оно как-то работает и выпускает игры :)

    И тут недавно, с подачи Leopotam, ещё одного любителя велосипедостроения и оптимизации всего, я решил автоматизировать этот процесс. В результате получился BASH скрипт, который умеет:

    • Скачивать последние изменения с GIT репозитория
    • Запускать тесты
    • Собирать APK для Android, в develop и release
    • Собирать для iOS Xcode проект, в develop и release
    • Компилировать его
    • Архивировать и экспортировать IPA
    • Генерировать для него манифест
    • Генерировать HTML страницы для установки
    • Загружать всё это на сервер с помощью sshpass
    • Складывать все логи в отдельную папку
    • Отсылать в Телеграмм уведомление

    И всё это по нажатию одной кнопки. Без запуска Unity и Xcode. Как-то по-веселее, да?

    image

    Теперь, когда сборка завершена, тестировщику приходит уведомление в Телеграмм с двумя ссылками на Android и iOS версии. Остаётся перейти по ним и установить приложение прямо с устройства. Под iOS тоже работает, для этого и генерируется специальный манифест.

    Вообще, это мой первый опыт в BASH программировании, поэтому не знаю, как оно, по фен-шую или нет, но работает исправно. В любом случае, скрипт будет допиливаться и изменяться под нужды проектов. Ниже несколько основных моментов, как что делается:

    Как запустить сборку Unity проекта под определенную платформу


    В мануале описаны все аргументы которые можно использовать для билда. Запускаем сборку APK:

    $UNITY -batchmode -quit -projectPath "$PATH" -executeMethod Game.BuildActions.AndroidDevelopment -buildTarget android -logFile "$LOGS_PATH/android_development.log"

    Тут -buildTarget как раз и задает платформу, а -executeMethod вызывает функцию в Unity проекте, которая запускает билд с заданными параметрами, выглядит это примерно так:

    static void AndroidDevelopment () {
    	PlayerSettings.SetScriptingBackend (BuildTargetGroup.Android, ScriptingImplementation.IL2CPP);
    	PlayerSettings.SetScriptingDefineSymbolsForGroup (BuildTargetGroup.Android, "DEV");
    	EditorUserBuildSettings.SwitchActiveBuildTarget (BuildTargetGroup.Android, BuildTarget.Android);
    	EditorUserBuildSettings.development = true;
    	EditorUserBuildSettings.androidETC2Fallback = AndroidETC2Fallback.Quality32Bit;
    	BuildReport report = BuildPipeline.BuildPlayer (GetScenes (), ANDROID_DEVELOPMENT_FILE, BuildTarget.Android, BuildOptions.None);
    	int code = (report.summary.result == BuildResult.Succeeded) ? 0 : 1;
    	EditorApplication.Exit (code);   
    }
    

    Тут можно задать свои параметры для билда, кондишны, и т.п. Результат возвращается в BASH скрипт.

    Как скомпилировать и экспортировать Xcode проект


    После того, как Unity успешно выдала Xcode проект, его надо скомпилировать, заархивировать и экспортировать в IPA файл, делается это примерно так:

    xcodebuild -project "$IOS_PATH/Unity-iPhone.xcodeproj" -quiet > "$LOGS_PATH/ios_build_release.log" 2>&1

    xcodebuild -project "$IOS_PATH/Unity-iPhone.xcodeproj" -scheme "Unity-iPhone" archive -archivePath "$IOS_RELEASE/Unity-iPhone.xcarchive" -quiet > "$LOGS_PATH/ios_archive_release.log" 2>&1
    

    xcodebuild -exportArchive -archivePath "$IOS_RELEASE/Unity-iPhone.xcarchive" -exportOptionsPlist "$IOS_RELEASE/options.plist" -exportPath $IOS_RELEASE -allowProvisioningUpdates -quiet > "$LOGS_PATH/ios_export_release.log" 2>&1


    Здесь options.plist – это специальный манифест в котором указывается, метод экспорта, TeamID и прочее. Все доступные параметры можно посмотреть по команде:

    xcodebuild -help

    При всех этих операциях указывается стандартный Unity-iPhone.xcodeproj, который генерирует Unity. Если у вас xcworkspace, то тут надо проверять его наличие и использовать.

    Как отправить сообщение в Телеграмм из BASH скрипта


    Нужно найти бота BotFather, написать ему /start, или /newbot, заполнить поля и получить сообщение с токеном и ссылкой на документацию. Чтобы отправить с помощью бота сообщение, надо выполнить такую команду:

    curl $BOT_PROXY https://api.telegram.org/bot$BOT_TOKEN/sendMessage -m 60 -s -X POST -d chat_id=$CHAT_ID -d text="$1" > "$LOGS_PATH/bot.log" 2>&1

    Тут CHAT_ID это идентификатор чата, куда отправлять сообщения. Можно например, добавить бота в группу где сидят тестировщики, дать ему права на чтение сообщений. После этого выполнить:

    https://api.telegram.org/bot[BOT_TOKEN]/getUpdates

    И получить ID группы и участников кто что-то писал. После этого указать ID группы или конкретного участника, кому отправлять. Как найти и настроить отправку через прокси, думаю не проблема.

    Остальные функции, патчат шаблоны манифестов и HTML с помощью sed и заливают нужные файлы на сервер с помощью sshpass.

    Параметры которые можно быстро поменять:

    
    # 
    # PARAMS TO CHANGE
    #
    
    BRANCH='master'
    
    COMPANY='my_company'
    GAME_NAME='new_game'
    BUNDLE='com.mygames.game'
    TEAM='ios_team_id'
    REMOTE_PATH='url_my_builds_server'
    
    SSH_LOGIN='my_login'
    SSH_PASS='my_pass'
    SSH_HOST='my_builds_server.ru'
    SSH_PATH='~/domains/my_builds_server.ru/builds'
    
    TEMPLATE_FILE=$(PWD)'/template.html'
    MANIFEST_FILE=$(PWD)'/manifest.plist'
    VERSION_FILE=$(PWD)'/version.txt'
    
    LOGS_PATH=$PROJECT_PATH'/Logs'
    ANDROID_PATH=$PROJECT_PATH'/Builds/Android'
    BUILDS_PATH=$PROJECT_PATH'/Builds'
    IOS_PATH=$PROJECT_PATH'/Builds/iOS'
    IOS_BUILD_PATH=$PROJECT_PATH'/Builds/iOS/build'
    IOS_DEVELOPMENT=$PROJECT_PATH'/Builds/iOS/build/development'
    IOS_RELEASE=$PROJECT_PATH'/Builds/iOS/build/release'
    
    BOT_TOKEN='my_bot_token'
    BOT_PROXY='--proxy 185.189.211.70:8080'
    CHAT_ID='123456798'
    
    UNITY='/Applications/Unity/Hub/Editor/2019.3.0f1/Unity.app/Contents/MacOS/Unity'
    
    #
    #
    #
    

    Демка и исходники



    Конечно, всё это можно было сделать через тот же Gitlab CI/CD, уже есть готовые скрипты для этого, запускать раннеры, собирать и тестировать. Короче использовать готовую инфраструктуру и механизмы. Но на него надо переезжать и тоже настраивать. Может к этому и придём, пока так и это намного лучше того что было. Тем более, что весь скрипт был написал достаточно быстро.

    Всем автоматизации в 2020 году! Вкалывают роботы, а не человек.
    Поддержать автора
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 5

      +1
      • Скачивать последние изменения с GIT репозитория


      И где все это? :)


      • Про options.plist — TeamId не нужен, он берется из архива, а вот


        <key>compileBitcode</key>
        <false/>

        сильно ускоряет подпись для dev-билдов.


      • Еще бы неплохо указать, что для сборки все-равно потребуется macos с xcode и установленными cli tools, а так же sshpass (через homebrew) если на sftp используются не ключи, а доступ по паролю.


      • Если используются нейтивные сдк, которые напрямую лезут к java и прочим штукам — скачиваемый jdk через unityhub не подойдет, т.к не прописаны в $PATH. Решение — прописывать их в $PATH перед запуском, либо поставить отдельно openjdk через homebrew. Второй способ удобнее, т.к юнити можно обновлять без проблем, а системный jdk останется и сам будет прописан в переменные окружения.


        0
        Да, косячок :) предыдущую версию запушил, надо обновить.

        Ну всё, понеслась… Я уже понял, у твоего велосипеда на 2 скорости больше)
          0

          Канешн, выбор бранча через через чат-бота (т.е можно прямо через него запрашивать билд нужного проекта с нужного бранча), автопрошивка хеша коммита с версией в сам билд и т.д и т.п :)


          Реализация через gitlab-runner неудобна тем, что фиче-бранчей может быть много и надо мочь собирать каждую из них отдельно — приходится их мерджить в билд-бранч, либо вешать теги, что очень не удобно. Поэтому вот такой автобилд по запросу оказался довольно удобным решением.

            0
            gitlab можно на мержреквесты настроить. И не принимать их)
            или настроить один дополнительный конвеер на все ветки, но с ручным запуском. тогда в коммите можно нажать кнопку и сбилдить. Либо автоматическом но первым условием сделать проверку какого нибудь флага)
            Последние два варианта правда будут засорят список работ в соответствующем разделе.

            А, ну и запускать ci можно через api, по кнопочке где нибудь. У нас в тележке кнопка.
              0

              ну в результате все-равно либо чистить руками, либо запускать руками. Дополнительный конвейер — теряется имя ветки-источника билда, сейчас в билд вшивается хеш коммита и имя ветки — удобно. Бот висит в группе и реагирует на команду в виде


              /build имя-проекта имя-ветки

              например


              /build supergame feature/new-ui

              В ту же группу сообщает о пройденных стадиях (скачивание репа, билд юнити, билд xcode, подпись, закачка на хостинг) и конечные линки для скачивания.

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое