11
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CircleCI 2.0でAndroidライブラリの自動デプロイ

Last updated at Posted at 2017-11-04

最近リリースされたCircleCI 2.0でAndroidライブラリをデプロイするまでをやってみたので、そのまとめ。

## 概要
今回CircleCIに対応させたのは以下のライブラリ
ChatMessageView

今回自動化したかったフローは

  1. 修正をGitHubへPush
  2. CircleCIでビルド&テスト
  3. Jfrog Bintrayにアップロード
  4. GitHubに自動でタグをPush
  5. READMEに記載しているライブラリのバージョンを書き換える

circle-ci-deploy.png

手順

1. CircleCIに登録

GitHubのアカウントがあれば、連携は簡単。
https://circleci.com/

2. プロジェクトの追加

サインアップが完了すると、PROJECTSタブからGitHubにあるレポジトリが読み込まれるので選択して追加できる。
レポジトリを選択するとAndroidの場合、デフォルトでOSはLinux、Platformは2.0,LanguageはGradle(Java)になっているのでデフォルト設定のままでOK。

3. プロジェクトに.circleci/config.ymlを追加

CircleCI 2.0では.circleci配下にconfig.ymlを置いて、そこに設定を書く。
レポジトリ連携後にサンプルのymlファイルが書いてあるのでそれを雛形にするとよさそう。

今回の設定内容は以下
https://github.com/bassaer/ChatMessageView/blob/master/.circleci/config.yml

config.yml
version: 2
jobs:
  build:
    branches:
      only:
        - master
        - develop
    docker:
      # specify the version you desire here
      - image: circleci/android:api-26-alpha

    environment:
      # Customize the JVM maximum heap limit
      JVM_OPTS: -Xmx3200m
      TERM: dumb

    steps:
      - checkout

      # Download and cache dependencies
      - restore_cache:
          key: jars-{{ checksum "build.gradle" }}-{{ checksum  "chatmessageview/build.gradle" }}

      - run:
          name: update android sdk
          command: |
              echo y | android update sdk --no-ui --all --filter tool,extra-android-m2repository,extra-google-google_play_services,extra-google-m2repository,android-26
              echo y | android update sdk --no-ui --all --filter build-tools-26.0.0
      - run:
          name: gradle dependencies
          command: ./gradlew androidDependencies

      - save_cache:
          paths: ~/.gradle
          key: jars-{{ checksum "build.gradle" }}-{{ checksum  "chatmessageview/build.gradle" }}

      # run unit tests!
      - run:
          name: unit test
          command: |
              ./gradlew test
              ./gradlew lint test
      - run:
          name: Show list of system-images
          command: sdkmanager --list --verbose | grep system-images

      - run:
          name: Setup Emulator
          command: sdkmanager "system-images;android-24;default;armeabi-v7a" && echo "no" | avdmanager create avd -n test -k "system-images;android-24;default;armeabi-v7a"

      - run:
          name: Launch Emulator
          command: export LD_LIBRARY_PATH=${ANDROID_HOME}/emulator/lib64:${ANDROID_HOME}/emulator/lib64/qt/lib && emulator64-arm -avd test -noaudio -no-boot-anim -no-window -accel on
          background: true

      - run:
          name: Wait emulator
          command: |
              circle-android wait-for-boot
              adb shell input keyevent 82
      - run:
          name: Run UI test
          command: ./gradlew example:connectedAndroidTest

      - run:
          name: Distribute Bintray
          command: |
              if [ $CIRCLE_BRANCH = "master" ]; then
                sh ./deploy.sh
              else
                echo "Bintray distribution was skipped."
              fi
      - run:
          name: Update version
          command: |
              if [ $CIRCLE_BRANCH = "master" ]; then
                sh ./version.sh
              else
                echo "Version update was skipped."
              fi
      - store_test_results:
          path: example/build/test-results

      - store_artifacts:
          path: example/build/reports
          destination: reports

今回の主な設定

masterブランチとdevelopブランチ以外のプッシュではCircleCIが走らないようする。

branches:
  only:
    - master
    - develop

使用するAndroid APIのバージョンを設定

docker:
  # specify the version you desire here
  - image: circleci/android:api-26-alpha

ここからは実際に動作させたいタスクを以下のように記述していく

- run:
    name: タスク名
        command: 実行したいコマンド

- run:
    name: 複数のコマンドがある場合
    command: |
       command1
       command2
      

sdkのアップデート
build.gradleで設定しているbuildToolsVersion等と合わせるるとよさそう。

- run:
    name: update android sdk
    command: |
      echo y | android update sdk --no-ui --all --filter tool,extra-android-m2repository,extra-google-google_play_services,extra-google-m2repository,android-26
      echo y | android update sdk --no-ui --all --filter build-tools-26.0.0

ユニットテストとLintチェックを実行

- run:
    name: unit test
    command: |
      ./gradlew test
      ./gradlew lint test

ここでは使えるsystem-imagesのリストを確認したかっただけなので本来は不要。

- run:
    name: Show list of system-images
    command: sdkmanager --list --verbose | grep system-images

emulatorを起動してEspressoでテストしたい場合は以下でemulatorの設定を行う。
今回はarmeabi-v7aが使えるのは24までで、別のsystem-imageだと起動できないことがあるのでひとまず24でセットアップ。

 - run:
    name: Setup Emulator
    command: sdkmanager "system-images;android-24;default;armeabi-v7a" && echo "no" | avdmanager create avd -n test -k "system-images;android-24;default;armeabi-v7a"

エミュレータの起動。

- run:
    name: Launch Emulator
    command: export LD_LIBRARY_PATH=${ANDROID_HOME}/emulator/lib64:${ANDROID_HOME}/emulator/lib64/qt/lib && emulator64-arm -avd test -noaudio -no-boot-anim -no-window -accel on
    background: true

エミュレータの起動に時間がかかるので待機。
スクリーンがロックされている場合があるのでadbのキーイベントを送って解除する。
公式ページには、この方法よりテストコードにスクリーン設定を記述するほうがよさそうと書いてあるが、 テストコードに記述した場合にもemulatorに接続できず失敗することがあったので、ひとまず両方記述。

- run:
    name: Wait emulator
    command: |
      circle-android wait-for-boot
      adb shell input keyevent 82

UIテスト実行。結構時間かかる。

- run:
    name: Run UI test
    command: ./gradlew example:connectedAndroidTest

ここまででビルド&テストは終了。
あとはJfrog Bintrayにデプロイする。
このあたりの処理はシェルスクリプトにまとめておくと管理しやすい。
以下では、CircleCIで用意された環境変数 $CIRCLE_BRANCH で実行中のブランチがわかるので、masterでテストまで成功したらdeploy.shを実行する。

- run:
    name: Distribute Bintray
    command: |
      if [ $CIRCLE_BRANCH = "master" ]; then
        sh ./deploy.sh
      else
        echo "Bintray distribution was skipped."
      fi

最後に、デプロイまでできたら、READMEに記載されているバージョンの書き換えとタグをGitHubへプッシュする。
上記と同様に一連の処理をシェルスクリプトにまとめて実行するだけ。
バージョンはbuild.gradleでも読み込みやすいようにversion.propertiesというファイルで管理している。

version.properties
version=1.4.0

READMEには以下のようにバージョン名を記述していたので、

dependencies {
    compile 'com.github.bassaer:chatmessageview:1.3.5'
}

バージョンの1.3.5の部分をsedコマンドで置換する。

version.sh
#!/bin/sh

VERSION=`cat version.properties | cut -d'=' -f2`

sed -i "/compile/s/[0-9]*\.[0-9]*\.[0-9]*/$VERSION/" ./README.md

以下は生成したタグとREADMEの変更をGitHutへプッシュする処理。
ポイントはコミットメッセージに[ci skip]を含めること。
これによってCircleCIが回り続けることを回避できる。

version.sh
# 続き

REPOSITORY="git@github.com:${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}.git"

git config --global user.name "CircleCI"
git config --global user.email "app.nakayama@gmail.com"

git add ./README.md
git commit -m "update version [ci skip]"

git tag -a $VERSION -m "version $VERSION"

git push origin master

git push origin --tags

4. SSHキーの設定

Circle CI連携時にGitHubの対象レポジトリに自動で読み取り専用の鍵が設定されるが、書き込みも行いたい場合は、
PROJECTS > 対象プロジェクトのSettings > SSH Permissions > Add SSH Key
から鍵の追加を行うことができる。

5. Status Budge

PROJECTS > 対象プロジェクトのSettings > Status Budges
からステータスバッジを生成してくれるのでREADMEなどに記載できる。
CircleCI

最後に

1.0からすこし書き方が変わっているので以下を参考にすると2.0へ移行しやすい。
https://circleci.com/docs/2.0/migrating-from-1-2/

emulator周りの設定で、同じ設定なのにemulatorが起動できなかったり、テストが失敗することがあった。
ダッシュボードからもう一度走らせると通ったりするので、謎。🤔
今回はひとまずデプロイまで自動でできる設定を行ったが、CircleCIはpushされたブランチをビルドするみたいなので、JenkinsみたいにPullRequestをトリガーに起動する方法もあるのか調査したい。

11
12
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?