コミットしたらテスト環境に自動でゲームをデプロイしてみました。

問題点

対応を入れたら、すぐ確認できる環境を作りたいが手作業ではめんどくさい。

解決策

上のような感じに、コミットしたらテスト用のビルド、デプロイまで自動で行うようにしました。

解決するためにやったこと

Githookのpre-commitの中身を変更する

githookはgitのコマンドを打った際に、特定の名前のファイルが存在すると、そのコマンドを打つ前後に指定したコマンドを実行してくれる機能です。

実行された結果が0なら成功と見なし、1なら失敗と見なしgitのコマンドを実行しません。


今回はそのうち、コミット前にコマンドを実行してくれるpre-commitを使用することにしました。

git statusでステージングされていなかったらコミットさせない

テスト失敗→修正を繰り返していると、git add忘れが何度か発生したため、この際未ステージングがあったらコミットしないようにしました。

それを実現するため、次のようなコードにしております。

git_status_check() {
    # ステージングされていない項目がないかチェックします。
    result=`git status -s | grep -e "^ " -e "?"`

    if [ -n "$result" ]; then
        echo "ステージングされていないファイルがあります。git statusでご確認ください。"
        exit 1
    fi    
}

このコードのキモはresultで実行しているgit status -s の結果でコミットするか否か決めているところでしょう。

git status -s と行うと、次のようにピックアップされます。

git status -s
M  PhoneTestUI.gd
 M project.godot
A  test2
?? test1

このコマンドを見ると、ステージングされていないのは先頭が空白か?になっているファイルなので、

実行結果をgrepして、空文字か否かで成否を判定しています。

ユニットテストで失敗があったらコミットしない

各機能の品質を確認するためにテストは不可欠です。

今回、Godotというゲームエンジンで作業を進めていましたが、Godotの外部ライブラリにGUTというユニットテストのライブラリがあるので、 そちらを使用して、ユニットテストが実行できるようにしました。


作成したコードは以下の通りです。

alias godot4='/Applications/Godot4-beta3.app/Contents/MacOS/Godot'

# ...

run_gut_test() {
    # godotのgutを実行します。
    #   全て合格    :0 
    #   失敗がある  :1
 
    godot4 --headless -s addons/gut/gut_cmdln.gd --path $PWD -gdir=res://test/unit -gexit
    result=$?
    if [ $result = 1 ]; then
        echo "Testに失敗しました。テストコードをご確認ください"
        exit 1
    fi
}

godot4 はコマンドが長いので、中でaliasにしています。こちらのコマンドはGUTのWikiを確認しながら作成しました。

他の環境で行う場合は、適宜読み替えてもらって、各自利用しているテストライブラリを実行する形にすれば流用可能かと思います。


それと注意点ですが、現在(2022/11/18時点)のGUTはテスト結果が0しか返らない状態のため、個人的に修正して使っていました。 Godot4用のGUTを使う方はご注意ください。

デバッグ用のビルドを行う

debug_build()
{
    _android_debug_build    
    _ios_debug_build
}

_android_debug_build()
{
    godot4 --headless --export-debug Android
    result=$?
    if [ $result = 1 ]; then
        echo "Androidのビルドに失敗しました。"
        exit 1
    fi
}

_ios_debug_build()
{
    godot4 --headless --export-debug iOS
    result=$?
    if [ $result = 1 ]; then
        echo "iOSのビルドに失敗しました。"
        exit 1
    fi
}

このコマンドは、あらかじめGUIで設定しておいたexport用のプリセットを使って、 Android用のapkファイル、iOS用のipaファイルをビルドすることができます。*1

引数で指定すれば、まとめられそうですがそれはTODOということにします。

Deploygateへアップロードする

export_deploygate()
{
    _export_android
    _export_ios
}

_export_android()
{
    dg deploy build/$(basename $(pwd)).apk
    result=$?
    if [ $result = 1 ]; then
        echo "DeployGateにAndroidビルドをアップロードしようとしたところ失敗しました。"
        exit 1
    fi       
}

_export_ios()
{
    dg deploy build/iOS/$(basename $(pwd)).ipa
    result=$?
    if [ $result = 1 ]; then
        echo "DeployGateにiOSビルドをアップロードしようとしたところ失敗しました。"
        exit 1
    fi           
}

Deploygateはテスト用のAndroid ,iOSのビルドを手軽に実機にインストールできるサービスです。

Deploygateにはdgコマンドから始まるCLIが用意されており、cacapon環境は事前にセットアップ済みだったため、そのままコマンドを使用することにしました。

こちらのコマンドを実行すると、指定したビルドの成果物をWeb上にアップロードすることができ、指定の手順をふめば実機にダウンロードすることが可能です。

結果

ご覧のように、コミットすると実機へ遊べる状態までなりました。

pre-commit完全版

#!/usr/local/bin/zsh
alias godot4='/Applications/Godot4-beta3.app/Contents/MacOS/Godot'

cd_project_root(){
    cd ~/workspace/Godot/Godot4.X/PhoneDeployTest
}

git_status_check() {
    # ステージングされていない項目がないかチェックします。
    result=`git status -s | grep -e "^ " -e "?"`

    if [ -n "$result" ]; then
        echo "ステージングされていないファイルがあります。git statusでご確認ください。"
        exit 1
    fi    
} 

run_gut_test() {
    # godotのgutを実行します。
    #   全て合格    :0 
    #   失敗がある  :1
 
    godot4 --headless -s addons/gut/gut_cmdln.gd --path $PWD -gdir=res://test/unit -gexit
    result=$?
    if [ $result = 1 ]; then
        echo "Testに失敗しました。テストコードをご確認ください"
        exit 1
    fi
}

debug_build()
{
    _android_debug_build    
    _ios_debug_build
}

_android_debug_build()
{
    godot4 --headless --export-debug Android
    result=$?
    if [ $result = 1 ]; then
        echo "Androidのビルドに失敗しました。"
        exit 1
    fi
}

_ios_debug_build()
{
    godot4 --headless --export-debug iOS
    result=$?
    if [ $result = 1 ]; then
        echo "iOSのビルドに失敗しました。"
        exit 1
    fi
}

export_deploygate()
{
    _export_android
    _export_ios
}

_export_android()
{
    dg deploy build/$(basename $(pwd)).apk
    result=$?
    if [ $result = 1 ]; then
        echo "DeployGateにAndroidビルドをアップロードしようとしたところ失敗しました。"
        exit 1
    fi       
}

_export_ios()
{
    dg deploy build/iOS/$(basename $(pwd)).ipa
    result=$?
    if [ $result = 1 ]; then
        echo "DeployGateにiOSビルドをアップロードしようとしたところ失敗しました。"
        exit 1
    fi           
}

cd_project_root
git_status_check
run_gut_test
debug_build
export_deploygate

exit $?

課題

  • 誰かに共有するとなると不十分
  • pre-commitの共有ができていない。
    • pre-commitは.git内にあるファイルのため、git管理下に置かれないため、そのままだと共有できない。
    • いくつかブログを参照したところ、.githookというディレクトリを作り、localでhookはそれを指定するというのが主流っぽい。
      • 結局初期化処理を挟まないといけないので、チーム共有としてはちょっと不便
  • デプロイしたデータを全ての環境で使いまわせるようにする。
    • 現状だとDebug専用になってしまっている。
    • デバッグもリリースも同じにして、設定ファイルの違いで変化させるようにしたい。
    • Godotでそれができるかは不明
  • Godotのエクスポート設定をCLI上で行う方法が分からない。
    • 現状はホスト環境でGUIを起動して一度設定する必要がある。(設定した後は使いまわせる)
  • DeploygateのCLICLI上から入手してインストールする方法。
    • ホームページからアクセスしてダウンロードする方法しかわからない。

*1:Godotではかくプラットフォーム用にアプリをビルドすることをexportと言っています