GitHub

独自のBitriseプロジェクトスキャナを作成する

Project Scanner (プロジェクトスキャナ) は与えられたプロジェクトのタイプを検知し、ベーシックなBitrise configurationを生成します。サポートされているプロジェクトのタイプそれぞれにはスキャナが付随しています:それらは個々のパッケージとして保管されています。

一つのプロジェクトタイプスキャナは最低2つのワークフローを定義します:テスト用 (primary)とビルド用 (deploy)になっています。実行を成功させるために、最低限の数のStepがすでに含まれております。

Build and test Steps ビルドとテストのStep

ビルドStepとテストStepにはそれぞれ異なったものが必要です:

  • ビルドStepはアプリのビルドをする必要があります。デプロイの準備が完了している状態で、アウトプットファイルへ環境変数を出力しなければなりません。例えば、iOSアプリをビルドするビルドStepは、.ipaファイル (.xcodearchiveではない) とその.ipaファイルへのパスを出力する必要があります。
  • テストStepはテスト結果を出力する必要があるので、bitrise.io上のビルドページにて確認することができます。

ウェブサイト上で新プロジェクトを追加する際やご自身のマシンでプロジェクトを開始する時、bitrise-initツールが全てのスキャナを通じてイテレーション作業を行います。ほかにも、scanner interface methods (スキャナインターフェース方法) をそれぞれに呼び出し、アウトプットを収集します。アウトプットに基づいてベーシックな設定が生成されます。

可能性のあるワークフローがscan result model (スキャン結果モデル)で表示されます。そのモデルは以下のように構成されています。

YAML内でのモデルのベーシックな構造は以下のようになっています:

options:
  DETECTED_PLATFORM_1: OptionModel
  DETECTED_PLATFORM_2: OptionModel
  ...

configs:
  DETECTED_PLATFORM_1:
    CONFIG_NAME_1: ConfigModel
    CONFIG_NAME_2: ConfigModel
    ...
  DETECTED_PLATFORM_2:
    CONFIG_NAME_1: ConfigModel
    CONFIG_NAME_2: ConfigModel
    ...
  ...

warnings:
  DETECTED_PLATFORM_1:
  - "warning message 1"
  - "warning message 2"
  ...
  DETECTED_PLATFORM_2:
  - "warning message 1"
  - "warning message 2"
  ...

Options (オプション)

Optionsは質問や質問への可能性のある回答を表示します。
例えば:

質問と回答はStepインプットへ翻訳されます。スキャナは、インプット値を決定する、もしくはユーザーに選択させる/値を入力させるのどちらかになります。

例えば、 Xcode Archive & Export for iOS Stepにはexport-methodと呼ばれるインプットがあります。これはエクスポートしたい.ipaファイルタイプのStepを通知します。この値はソースコードに基づいた決定はできないので、スキャナは全ての可能性のある値を収集してリスト化し、ユーザーに選択させる方法をとっています。

オプションを選択してチェーンを開始することができます:これで後からでも異なるオプションが表示されるようになります。例えば、テストターゲットに関連したXcodeスキームを選択した場合、また違った”questions” に導かれます。同様に、特定のオプションを選択することにより、後々生成される異なるワークフローへ導かれるようになっています。

オプションモデル

OptionModel (オプションモデル) はインプットオプションを表します。Goではこのように表示されます:

// OptionModel ...
type OptionModel struct {
    Title  string
    EnvKey string

    ChildOptionMap map[string]*OptionModel
    Config         string
}

Schemeインプット用に値を選択するというシナリオがあるとします。options内にvalue_mapがあることを確認します。可能性のある値は以下の通りです:

SchemeWithTestを選択すると、次はテスト実行に使用されたシミュレータに関連したオプションが表示されます。

SchemeWithoutTestを選択すると、次は.ipaファイル用のエクスポート方法についてのオプションが表示されます。

{
    "title": "Scheme",
    "env_key": "scheme",
    "value_map": {
        "SchemeWithTest": {
            "title": "Simulator name",
            "env_key": "simulator_name",
            ...
        },
        "SchemeWithoutTest": {
            "title": "Export method",
            "env_key": "export_method",
            ...
        }
    }
}

Every option chain has a first option: this is called head. The possible values of the options can branch the option chain.

Every option branch’s last options must have a config property set. config holds the id of the generated Bitrise configuration.

An options chain’s last options cannot have a value_map.

全てのオプションチェーンにはheadと呼ばれる、最初のオプションがあります。可能性のあるオプションの値は、オプションチェーンをブランチすることができます。

全てのオプションブランチの最後のoptionsにはconfigプロパティセットがある必要があります。configは生成されたBitrise configurationのIDを保持しています。

オプションチェーンの最後のoptionsではvalue_mapを保持することはできません。

{
    "title": "Scheme",
    "env_key": "scheme",
    "value_map": {
        "SchemeWithTest": {
            "title": "Simulator name",
            "env_key": "simulator_name",
            "value_map": {
                "-": {
                    "config": "bitrise_config_with_test",
                }
            }
        },
        "SchemeWithoutTest": {
            "title": "Export method",
            "env_key": "export_method",
            "value_map": {
                "development": {
                    "config": "bitrise_config_without_test",
                },
                "app-store": {
                    "config": "bitrise_config_without_test",
                },
                "ad-hoc": {
                    "config": "bitrise_config_without_test",
                }
            }
        }
    }
}

スキャナ

スキャナはプロジェクトタイプに応じたoptions用に可能性のあるoptionsチェーンとワークフローを生成します。ActiveScanner変数がそれぞれのスキャナの実装を保持します。すべての特定のスキャナはScannerInterfaceを実行します。

// ScannerInterface ...
type ScannerInterface interface {
    Name() string
    DetectPlatform(string) (bool, error)

    Options() (models.OptionModel, models.Warnings, error)
    Configs() (models.BitriseConfigMap, error)

    DefaultOptions() models.OptionModel
    DefaultConfigs() (models.BitriseConfigMap, error)

    ExcludedScannerNames() []string
}

スキャナのテスト

スキャナをテストするには、ユニットテストとインテグレーションテストの両方が必要になります。

ユニットテストはGoのStandard testing libraryを使用して書かれています。

インテグレーションテストを行うために、Bitriseはプロジェクトタイプスキャナがプロジェクトタイプの例を基に、希望するBitriseの構成を生成しているかどうかを検証します。これを行うために、Bitriseは新しいスキャナを使って指定されたサンプルプロジェクトをスキャンして、インテグレーションテストに合致するように、生成されたスキャン結果を修正します。

修正する理由としては、スキャナが生成された構成にStepを追加しているからですが、Stepのバージョンは随時更新されます。Stepバージョンの定義はsteps/const.goで確認することができます。

まず、サンプルプロジェクトのルートディレクトリ内のbitrise-init --ci config を呼び出します。そして生成された scan_result.yml ファイル内のStepバージョンを%sを使って変更します。定義された最新のStepバージョンを構成内へfmt.Sprintfを使用し注入します。

インテグレーションテストでは、スキャナによって生成されたscan_result.ymlファイルと以前に生成されたreference scan_result contentを照合します。

独自のスキャナを提出する

ご自身のスキャナをBitriseに提出することができます:まずBitriseがレビューを行い、承認されるとbitrise-initツールへインテグレートされます!

新規のスキャナー用の開発パスはご自身のサンプルプロジェクトを使って開始され、プロジェクトタイプ用の既存のStepをアップデートして終了します。一つずつ見ていきましょう。

  1. プロジェクトタイプを代表するインスタンスを実証するオープンソースのサンプルアプリを探すまたは作成します。

    以下のものを含める必要があります。

    • readmeファイル (プロジェクトのアップデート、ビルド、テストを行うツールのバージョンを含む)
    • ご自身のスキャナーによって生成されたbitrise.ymlファイル
  2. 既存するStepやカスタムスクリプトを使ってサンプルアプリのビルド、テストを行います。
  3. 新規のプロジェクトタイプが必要とする、不足しているStepを作成します。スキャナーを一度作成すると、これらのStepのプルリクエストはスキャナーのプルリクエストとリンクさせる必要があります。
  4. プロジェクトタイプ用のスキャナーを作成します。
  5. 必要なユニットテストとインテグレーションテストを行います。
  6. bitrise-initプロジェクトへのスキャナープルリクエストを開きます。

    It should:

    • 新規プロジェクトタイプのサンプルアプリをリンクさせます。
    • 新規プロジェクトタイプのテストとビルド用のガイドをリンクさせます。
    • 新規プロジェクトタイプのアイコンを含めます (しない場合はBitriseが自動で作成します)。
    • 新規プロジェクトタイプのビルドとテスト用のツールをリスト化したデフォルトスタックを推奨します。
  7. 必要であれば、新規プロジェクトタイプを使って既存のStepをアップデートすることができます。それらのStepのプルリクエストはスキャナーのプルリクエストとリンクしている必要があります。