iOS・SwiftプロジェクトのCI/CDで、bitrise.ymlをリポジトリ内で管理する

はじめに


普段は、CircleCI をメインで使っていますが、モバイルアプリの CI/CD で流行っているBitriseを少し触ってみて、CircleCI と同じようにリポジトリ内で、設定ファイルを管理したくなったので、その設定方法に関する記事です。

モチベーション


人・文化・サービスによって、bitrise の設定(bitrise.yml)をbitrise GUIで管理する or リポジトリで管理するについては議論があると思います。ちょっとワークフローの流れを試してみたいとかなら、GUI でもいいと思いますが、 基本的には、リポジトリで管理する方が自分は良いと思っています。 以下、自分なりにそれぞれのメリット・デメリットに関して整理してみました。

メリット・デメリット


◯ bitrise GUI

■ メリット

  1. ワークフローが 視覚的に 確認できる
  2. GitHub 等のソースコード管理ツールの権限を持っていなくても、ワークフローの参照・編集ができる
  3. bitrise GUI でワークフローの差分管理もできる

■ デメリット

  1. bitrise GUI を見に行かないと(権限がないと)、どういうワークフローになっているのかを確認できない。(そもそもそのリポジトリがなんの CI が動いているのか、リポジトリからは判断できない。)
  2. 他の CI/CD サービス(CircleCI, TravisCI etc…)は基本的にリポジトリで管理することを前提としているものもまぁまぁ多く、同じノリではいかないので、そういったサービスを使ってた人は、ちょっと戸惑う。
  3. ワークフローを修正するときに、レビュー・反映するまでのフローが仕組み化されていない。(Git Flow, GitHub Flow が使えない?)

◯ リポジトリで管理

■ メリット

  1. bitrise GUI を見に行かずに、リポジトリの bitrise.yml を見れば、ワークフローの流れが確認できる。
  2. 他の CI/CD サービス(CircleCI, TravisCI etc…)と同じノリで使える。
  3. Git Flow, GitHub Flow が使える。

■ デメリット

  1. GitHub の権限がないと、対象 app のワークフローの流れが 視覚的に パッとわからない。(build の log を見れば、何がどの順番で実行されているかはまぁわかる。)
  2. GUI では、ワークフローの変更はできない。
  3. ワークフローで変更した内容を反映させて、CI を試したい場合は、都度 git commit しないといけないので、少し面倒。かつ、git が汚くなるかも。

実際にやってみた


実際にやったこととしては

  1. 事前に、bitrise 管理画面からトリガーとなるワークフローを作成する
  2. リポジトリ内の bitrise.yml 等の設定ファイルを作成する

の2つです。以下その詳細を記載します。

1. 事前に、bitrise 管理画面からトリガーとなるワークフローを作成する


上記で、リポジトリで管理すると記載しましたが、 bitrise は全てのワークフローをリポジトリで管理するわけではありません。 構造としては以下のようになっています。その理由に関しては、 リポジトリに bitrise.yml を保存する潜在的な問題 を参考にしてください。

1.1. 大まかな流れ


  1. まず、bitrise GUI から作成したワークフローをトリガーとして CI が起動する。
  2. そのワークフローがリポジトリ管理されている bitrise.yml をキックする(起動する)。

1.2. bitrise 管理画面からワークフローを作成する


やることは、以下の cirun_from_repo の 2 つだけです。

■ ci

名前は ci ではなくてもなんでも良いが、リポジトリ内の bitrise.yml で定義するワークフローと同じ名前に合わせる必要がある。
多分、↑ ここ、最初みんなハマるかなと思うので、要注意です!!!やることとしては、run_from_repoを起動するだけ。
c.f. bitrise.yml をリポジトリ内で管理するための手引き#はまった点

■ run_from_repo

実際の bitrise GUI 上から作成するワークフロー(今回の場合は、ciというワークフロー)は、以下の通りです。

---
format_version: "8"
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
project_type: ios
trigger_map:
  - push_branch: "*"
    workflow: ci
  - pull_request_target_branch: "*"
    workflow: ci
workflows:
  ci:
    after_run:
      - run_from_repo
  run_from_repo:
    steps:
      # git cloneするためのkeyのsetup
      - activate-ssh-key:
          run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
      # 対象のリポジトリを `git clone` する。
      - git-clone: {}
      # git cloneされたリポジトリ内で管理された `bitrise.yml` をみて、対象のワークフローを起動する。
      - script:
          title: continue from repo
          inputs:
            - content: |-
                #!/bin/bash
                set -ex
                # この場合 `bitrise run ci` が実行される。
                # リポジトリ内のbitrise.ymlの ci というワークフローを実行する。
                bitrise run "${BITRISE_TRIGGERED_WORKFLOW_ID}"                

ちなみに余談ですが、公式ドキュメントに合わせて、after_run を使って ci -> run_from_repo と実行するように記載しましたが、試していないのですが、直接指定しても動作としては、問題ないと思います。

# e.g. after_runを使わずに、直接指定する場合
workflows:
  ci:
    steps:
      - activate-ssh-key:
          run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
      - git-clone: {}
      - script:
          title: continue from repo
          inputs:
            - content: |-
                #!/bin/bash
                set -ex
                bitrise run "${BITRISE_TRIGGERED_WORKFLOW_ID}"                

ただ

  1. activate-ssh-key
  2. git-clone
  3. script

この部分を run_from_repo というワークフローで 共通化する ことで、ワークフローの管理を少なくすることができるので基本的には after_runを使った公式ドキュメントのやり方をすることが推奨されているのだと思います。

2. リポジトリ内の bitrise.yml 等の設定ファイルを作成する


さて、bitrise GUI 上での設定は終わりました。
あとは、いつも通りローカルで、エディタを開いて、対象のリポジトリに設定ファイルを追加するだけです。結論今回試したのは、Swift のプロジェクトだったので、用意したのは、以下の 3 つのファイル。

$ tree -L 2
.
├── Dangerfile
・・・
├── bitrise.yml
├── fastlane
│   └── Fastfile
・・・

bitrise.yml

---
format_version: "8"
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
project_type: ios
workflows:
  ci:
    steps:
      # fastlaneでSwiftLintを動かしたい場合、事前にInstallしないとダメっぽい?
      - script:
          title: Install SwiftLint
          inputs:
            - content: |-
                #!/bin/bash
                set -ex
                curl -s -L -O https://github.com/realm/SwiftLint/releases/download/0.38.2/SwiftLint.pkg > /dev/null
                sudo installer -pkg SwiftLint.pkg -target / > /dev/null
                rm SwiftLint.pkg                
      # fastlaneで、build laneを実行する
      - fastlane:
          inputs:
            - lane: build
      # bitriseに swiftlint の結果を artifact としてuploadする
      - deploy-to-bitrise-io:
          inputs:
            - deploy_path: "swiftlint-output.html"
      # 結果をSlack通知
      - slack:
          inputs:
            - title: ""
            - emoji: ""
            - emoji_on_error: ""
            - webhook_url: https://hooks.slack.com/services/xxxxxx/xxxxxx/xxxxxx # Slack の incoming webhook url
            - channel: "#bitrise-ci"
            - message: ""
            - message_on_error: ""
            - icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
            - icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
            - fields: |
                App|${BITRISE_APP_TITLE}
                Branch|${BITRISE_GIT_BRANCH}
                Message|${BITRISE_GIT_MESSAGE}
                Workflow|${BITRISE_TRIGGERED_WORKFLOW_ID}                

Fastlane

  1. Swiftlint
  2. danger

を実行するだけ。

fastlane_version "2.140.0"
default_platform :ios

lane :build do |options|
  danger(use_bundle_exec: true) # use_bundle_execをtrueにする必要あったか不明。。すいません。

  swiftlint(
    mode: :lint,
    reporter:    "html",
    output_file: "swiftlint-output.html",
    config_file: ".swiftlint.yml",
  )
end

Dangerfle

とりあえず、wip だったら warn するだけ。

has_label_wip = github.pr_title.match(/WIP/i) || github.pr_labels.include?('wip') || github.pr_labels.include?('Wip') || github.pr_labels.include?('WIP')
warn("PR is Work in Progress") if has_label_wip

実行する

あとは、これらのファイルを対象リポジトリに追加、commit して、push するだけ。

bitrise の log を管理画面から確認してみると

bitrise-from-repo bitrise-artifact

こんな感じで成功です! 今後これをベースに bitrise.yml を改善していこうと思っています。

さいごに

今まで bitrise 触ったことなかったですが、いい感じにベースは設定できたのかなという感じでした。 fastlane も初めて触ったのですが、色々便利だなーと思いました。 iOS で構築している CI の Workflow 紹介の記事の中で紹介しているように、bitrise のワークフローではなく、Fastlane でメイン部分のワークフローを管理すれば、実質今回やりたかった「ワークフローを git で管理すること」は満たせる感じはあるので、まずそちらをやってみて、それでもワークフローの管理に課題感を感じたら、本記事のように bitrise.yml も git で管理することも検討してみるといいのかなと思いました。

参考