GitLabにはCI(Continuous Integration: 継続的インテグレーション)機能があります。GitLabのCIを使えば、CI専用の別ソリューションを導入せずに、継続的インテグレーションを行えます。
この記事では、コードをGitLabにプッシュした際に、XCTestを起動し、macOSアプリやiOSアプリのユニットテストを自動実行する設定方法について説明します。
Runnerの登録
GitLabのCI/CDはRunnerが動いて処理を実行します。Runnerにはプロジェクト間で共有する「Shared Runner」と、特定のプロジェクト専用の「Specific Runner」があります。
今回は複数のプロジェクト(リポジトリ)で利用可能な「Shared Runner」を登録する手順を紹介します。
Runnerのインストール
XCTestを実行するために使用するRunnerなので、XCTestを実行するMacにインストールします。ここでは例として、Mac Miniにインストールする手順を説明します。
macOSへのGitLab Runnerのインストール方法は公式サイトに書かれています。
ダウンロードするバイナリは、Intel Mac版とApple Silicon版とで異なります。ターミナルからcurl
でダウンロードします。
- Intel Mac版
sudo curl --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64"
- Apple Silicon版
sudo curl --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-arm64"
ダウンロードされたRunnerは/usr/local/bin/gitlab-runner
に保存されます。
sudo chmod +x /usr/local/bin/gitlab-runner
cd ~
gitlab-runner install
gitlab-runner
のロケールを設定します。~/Library/LaunchAgents/gitlab-runner.plist
ファイルを開きます。このファイルはgitlab-runner install
によって作成されます。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- 省略 -->
<key>EnvironmentVariables</key>
<dict>
<key>LC_ALL</key>
<string>en_US.UTF-8</string>
</dict>
</dict>
デフォルトの出力先は、通常ユーザーには書き込み権限がないディレクトリのため、gitlab-runner
が起動しません。書き込みできるように、StandardOutPath
とStandardErrorPath
の値を書き込み可能なファイルパスに変更します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- 省略 -->
<key>StandardOutPath</key>
<string>/Users/USER_NAME/.gitlab-runner/gitlab-runner.out.log</string>
<key>StandardErrorPath</key>
<string>/Users/USER_NAME/.gitlab-runner/gitlab-runner.err.log</string>
gitlab-runner start
Runnerの登録
MacにインストールしたRunnerをGitLabに登録します。
(1) Admin Area
のRunners
を開きます。
(2) Register an instance runner
をクリックします。次にShow runner installation and registration instructions
をクリックします。
(3) 詳細手順が表示されるので、Environment
からmacOS
を選択し、Command to register runner
という欄の横のコピーボタンをクリックします。コマンドがコピーされます。Close
をクリックして閉じる。
(4) RunnerをインストールしたMacのターミナルで、(3)でコピーしたコマンドを実行します。注意点として、XCTestをMac上で実行する際はユーザーモードが必要となるため、sudo
を付けずにコマンドを実行します。
実行すると、設定を対話型で聞かれるので、順番に入力します。
(5) GitLabのURLを入力します。
Runtime platform arch=amd64 os=darwin pid=10297 revision=76984217 version=15.1.0
Running in system-mode.
Enter the GitLab instance URL (for example, https://gitlab.com/):
[http://code.rkdev.corp/]:
(6) 登録トークンを確認されます。コマンド実行時にすでにトークンを指定しているので、Enterキーを押すだけでOKです。
Enter the registration token:
[-ABCDEFG4567890YZABC]:
(7) Runnerの説明を指定します。とりあえず、マシン名を入力しました。
Enter a description for the runner:
[MacMini2020.local]: MacMini2020
(8) Runnerに指定するタグを入力します。本記事の例では、Runnerは次の条件に対応しています。
- Macである
- Intel Macである
- OSは常に最新を使う予定である
これらを踏まえて、次の3つのタグを設定しました。
- mac
- mac-intel
- mac-intel-latest
Enter tags for the runner (comma-separated):
mac,mac-intel,mac-intel-latest
(9) メンテナンス用のメモを指定します。とくにないので空欄のままにしました。
Enter optional maintenance note for the runner:
(10) Executerを設定します。公式サイトにmacOSアプリやiOSアプリの場合はshell
を使うように書かれているので、shell
を指定します。
Registering runner... succeeded runner=-ABCDEFG
Enter an executor: custom, parallels, shell, ssh, kubernetes, docker, docker-ssh, virtualbox, docker+machine, docker-ssh+machine:
shell
(11) 登録が成功すると次のように出力されます。
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
(12) Admin Area
のRunners
ページを再読込すると、登録したRunnerが表示されます。
CI/CDの設定
テスト用のリポジトリとコードを用意してCI/CDを設定します。
テストコード
ここでは、GitLabのCIによって、XCTestが動くことを確認したいだけなので、次のような必ずエラーになるテストコードと必ず成功するテストコードを入れたユニットテストにしました。具体的な機能などをテストしているわけではなく、XCTestが正常に動作することを確認するためのコードであるため、「テストコード」と呼ぶことに何かしら違和感を覚えるかもしれません。しかし、ここではそのように呼称します。
import XCTest
@testable import CITest
class CITestTests: XCTestCase {
override func setUpWithError() throws {
}
override func tearDownWithError() throws {
}
func testExample() throws {
XCTFail("TEST FAILURE")
}
func testSuccess() throws {
XCTAssertTrue(true);
}
}
Shared Runnerを有効化する
リポジトリ単位で、Shared Runnerを有効化する必要があります。
(1) プロジェクトのSettings
のCI/CD
を開く。
(2) Runners
のExpand
をクリックします。
(3) Enable shared runners for this project
をオンにする。
CI/CDの設定ファイルを追加する
次のように操作して、CI/CDの設定ファイルを追加します。
(1) Webブラウザでリポジトリのページを開き、Set up CI/CD
リンクを開く。
(2) Create new CI/CD pipeline
をクリックする。
(3) Browse templates
をクリックし、Swift.gitlab-ci.yml
を開き、内容をコピーする。
(4) 自分のリポジトリのPipeline Editorに戻り、コピーした設定を貼り付ける。
(5) Xcodeのプロジェクトファイル名、スキーム名などを変更する。例えば、次の設定ファイルは以下の値を変更しています。
設定 | 値 |
---|---|
-project | CITest.xcodeproj |
-scheme | CITest |
-destination | iOS Simulator,name=iPhone 13,OS=15.5 |
tags | mac-intel-latest |
-archivePath | build/CITest |
-archivePath | build/CITest.xcarchive |
-exportPath | build/CITest.ipa |
-exportProvisioningProfile | “” |
paths: | build/CITest.ipa |
stages:
- build
- test
- archive
- deploy
build_project:
stage: build
script:
- xcodebuild clean -project CITest.xcodeproj -scheme CITest | xcpretty
- xcodebuild test -project CITest.xcodeproj -scheme CITest -destination 'platform=iOS Simulator,name=iPhone 13,OS=15.5' | xcpretty -s
tags:
- mac-intel-latest
archive_project:
stage: archive
script:
- xcodebuild clean archive -archivePath build/CITest -scheme CITest
- xcodebuild -exportArchive -exportFormat ipa -archivePath "build/CITest.xcarchive" -exportPath "build/CITest.ipa" -exportProvisioningProfile ""
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
artifacts:
paths:
- build/CITest.ipa
tags:
- mac-intel-latest
CIによるテストのみが必要で、アーカイブは不要な場合には、archive_project
ジョブを削除して、次のような設定ファイルにします。筆者の場合はこちらの設定が必要でした。
stages:
- build
- test
- archive
- deploy
build_project:
stage: build
script:
- xcodebuild clean -project CITest.xcodeproj -scheme CITest | xcpretty
- xcodebuild test -project CITest.xcodeproj -scheme CITest -destination 'platform=iOS Simulator,name=iPhone 13,OS=15.5' | xcpretty -s
tags:
- mac-intel-latest
-destination
オプションの指定については次の記事を参照してください。
(6) Commit changes
をクリックする。
テスト
作成したテストコードをリポジトリにプッシュします。必ず失敗するテストなので、しばらくしてジョブが失敗し、エラー通知のメールが来ます。
プロジェクトのCI/CD
のPipelines
を開きます。失敗したジョブが表示されるので、failed
をクリックします。
Failed Jobs
タブを開きます。予定通りテスト失敗でエラーになっている場合は、次のように失敗したテストのテストケース(メソッド)名が出力されます。
2022-06-27 18:59:30.903 xcodebuild[18902:109049] [MT] IDETestOperationsObserverDebug: 0.000 sec, +0.000 sec -- start
2022-06-27 18:59:30.903 xcodebuild[18902:109049] [MT] IDETestOperationsObserverDebug: 104.154 sec, +104.154 sec -- end
Failing tests:
CITestTests:
CITestTests.testExample()
** TEST FAILED **
ERROR: Job failed: exit status 1
それ以外のエラーが出ている場合は、ログの内容を見て、設定などを見直してください。
UIテスティングについて
この記事ではXCTestを使ったユニットテストしか行っていませんが、UIテスティングについても変わりません。
XcodeのプロジェクトにUIテスティングのテストパッケージが入っていて、スキームのテストプランに登録されていれば、Xcodeから手動でテストするときと同じように、UIテストも自動的に実行されます。
トラブルシューティング
私が設定したときに遭遇したエラーと対応方法を掲載します。
ユーザーがログインしているときしか動かない
XCTestを実行するのはログイン中のカレントユーザーである必要があります。そのため、Runnerを動かすMacはログイン状態でなければなりません。
マシンを再起動したとき
公式の手順にしたがってインストールするとサービスとして登録されます。サービスとして登録することによりマシンを再起動したときも、ログインさえすれば、Runnerが起動します。
状態がpending
のまま
状態がpending
のままとなり、パイプラインのbuild_project
を確認すると、タグに対応したRunnerが存在しないというエラーが表示されます。
このケースの場合は、次のような原因が考えられます。
tag
が間違っている。Shared Runner
を使おうとしているが、プロジェクトでShared Runner
が有効になっていない。- Mac上のRunnerがユーザーモードで動作していない。
2はこのページの「Shared Runnerを有効化する」を参照してください。
3は私がはまりました。Runnerを登録するときに、GitLabが出力したコマンドラインはsudo
が付いています。そのまま実行すると、ユーザーモードでRunnerが動かないので、XCTestも動作しません。
シミュレータ名やOSバージョンが間違っている
この場合、build_project
のログの中に次のようなエラーが出力されていて、使用可能なシミュレータとOSの組み合わせが列挙されています。
xcodebuild: error: Unable to find a destination matching the provided destination specifier:
.gitlab-ci.yml
ファイル内で指定する値を適切な値に修正しましょう。
プロジェクトのCI/CD
のEditor
を開くと、.gitlab-ci.yml
ファイルをWebブラウザ内で編集してコミットできます。
シミュレータ名やOSバージョンの指定方法については、次の記事を参照してください。