12
4

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 3 years have passed since last update.

Github ActionsとCircleCIの組み合わせが最高という話【後編】

Posted at

前回の記事

何をGithub Actionsで処理して、何をCircleCIで処理するか
どうやって実現するかを前回書きました

今回は実際にコードを見ながらどう実現するかを解説していきます。

おさらい

まずおさらいです。

Github Actions
ビルド
Lintチェック

CircleCI
テスト
Slackへの通知
自動マージ
デプロイ

※僕はAndroidエンジニアのためビルド等は基本Androidコマンドを叩いています。ご了承ください。
※Github Actions, CircleCIの細かい文法に関しては説明しません。

ビルド

name: Build

on:
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: Build with Gradle
        run: ./gradlew compileDebugSources

ここは簡単
純粋にGithub Actionsの処理を書いてあげればOK

Lintチェック

name: Build

on:
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: Build with Gradle
        run: ./gradlew lintDebug

本当はマルチモジュールでかつDangerを使ってGithubのコメントに結果を表示していますが、ここでは割愛
詳しくは以下の記事へ
https://qiita.com/dosukoi_android/items/75b9fe01aa021296d586

テスト

ここからが本題
先にGithub Actionsのワークフローを全て掲載し最後にCircleCIのワークフローを掲載します(CircleCIはconfig.ymlで一元管理しているため)
今回はレビュワーがapproveをしたらテストを走らせます。

Github Actions

name: UnitTest

on:
  pull_request_review:
    types: [ submitted ]

jobs:
  test:
    # ここでapproveされたらというハンドリング&Git-flowを使用している場合はブランチ名でもハンドリング
    if: ${{ github.event.review.state == 'approved' && github.event.pull_request.base.ref == 'master' }}
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Call CircleCI API
        # ここでCircleCIのAPIを叩く
        run: |
          curl \
          -X POST \
          -H "Content-Type: application/json" \
          -d '{ "branch": "master", "parameters": { "build_variant": "dev", "task": "test", "pull_request_title": "${{ github.event.pull_request.title }}", "pull_request_html_url": "${{ github.event.pull_request.html_url }}", "pull_request_user": "${{ github.event.pull_request.user.login }}", "pull_request_url": "${{ github.event.pull_request.url }}", "pull_request_sha": "${{ github.event.pull_request.head.sha }}"}}' \
          https://circleci.com/api/v2/project/github/${{ github.event.repository.full_name }}/pipeline

デプロイ

Github Actions


name: Deploy

on:
  pull_request:
    types: [closed]
    branches: [master]

jobs:
  build:
    # PRがcloseかつmergedがtrueの時だけ→つまりマージされた時だけ起動
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-18.04

    steps:
      - uses: actions/checkout@v1
      - name: Call CircleCI API
        run: |
          curl \
          -X POST \
          -H "Content-Type: application/json" \
          -H "Circle-Token: ${{ secrets.CIRCLE_TOKEN }}" \
          -d '{ "branch": "master", "parameters": { "build_variant": "dev", "task": "deploy", "pull_request_title": "${{ github.event.pull_request.title }}" } }' \
          https://circleci.com/api/v2/project/github/${{ github.event.repository.full_name }}/pipeline

CircleCI


version: 2.1

parameters:
  # これでどのジョブを起動するかハンドリング
  task:
    type: enum
    enum: ["deploy", "test"]
    default: "deploy"
  # 環境ごとにも変えられる
  build_variant:
    type: enum
    enum: ["dev", "stg", "production"]
    default: "dev"
  # ここから下はSlack通知で使用
  pull_request_title:
    type: string
    default: ""
  pull_request_html_url:
    type: string
    default: ""
  pull_request_url:
    type: string
    default: ""
  pull_request_user:
    type: string
    default: ""
  pull_request_sha:
    type: string
    default: ""

executors:
  android:
    docker:
      - image: circleci/android:api-30
    environment:
      JVM_OPTS: -Xmx1536m
      GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xmx1536m -XX:+HeapDumpOnOutOfMemoryError" -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false'


orbs:
  android: circleci/android@0.2.1

jobs:

  deploy:
    executor: android
    steps:
      - checkout
      - run:
          # aabファイルを作成する
          name: Build with Gradle
          command: |
            ENV=(<< pipeline.parameters.build_variant >>)
            ENV_UPPER_CASE=${ENV[@]~}
            ./gradlew ":navigation:phone:bundle${ENV_UPPER_CASE}Release"
      - run:
          # DeployGateのAPIを叩く
          name: Distribute App
          command: |
            curl \
            -H "Authorization: token $DEPLOY_GATE_API_KEY" \
            -F "file=@navigation/phone/build/outputs/bundle/<< pipeline.parameters.build_variant >>Release/phone-<< pipeline.parameters.build_variant >>-release.aab" \
            -F "message=<< pipeline.parameters.pull_request_title >>" \
            -v "https://deploygate.com/api/users/$DEPLOY_GATE_USER_NAME/apps"


  test:
    executor: android
    steps:
      - checkout
      - run:
          name: Unit Test
          command: |
            ENV=(<< pipeline.parameters.build_variant >>)
            ENV_UPPER_CASE=${ENV[@]~}
            ./gradlew "test${ENV_UPPER_CASE}DebugUnitTest"
      - run:
          # 失敗したらSlack通知
          when: on_fail
          name: Unit Test Failure Notification
          command: |
            curl \
            -X POST \
            -H "Content-Type: application/json" \
            -d '{"attachments": [{"color": "#D73A49", "title": "<< pipeline.parameters.pull_request_title >>", "title_link": "<< pipeline.parameters.pull_request_html_url >>", "text": "Failure Unit Test", "author_name": "<< pipeline.parameters.pull_request_user >>"}]}' \
            $SLACK_WEBHOOK

  auto_merge:
    executor: android
    steps:
      - run:
          name: Wait For Status Check
          command: sleep 5s
      - run:
          # GithubのマージのAPIを叩く
          name: Auto Merge
          command: |
            curl \
            -X PUT \
            -H "Authorization: token $PERSONAL_ACCESSTOKEN" \
            -H "Content-Type: application/json" \
            -d '{"sha": "<< pipeline.parameters.pull_request_sha >>", "merged": "true", "message": "Pull Request successfully merged"}' \
            "<< pipeline.parameters.pull_request_url >>/merge"


workflows:
  version: 2.1
  build_and_deploy:
    # APIを叩くときのパラメータがdeployの時にこのジョブを起動
    when:
      equal: [deploy, << pipeline.parameters.task >>]
    jobs:
      - deploy:
          name: Deploy

  test:
    # APIを叩くときのパラメータがtestの時にこのジョブを起動
    when:
      equal: [test, << pipeline.parameters.task >>]
    jobs:
      - test
      - auto_merge:
          name: Auto Merge
          requires:
            - test
     # testというジョブが終わったらauto_mergeというジョブを起動

まとめ

以上となります。

ビルドからデプロイまでほぼ自動化し、マンパワーで行うことはレビューだけです。
コンフリクトさえしてなければ、レビュワーがLGTM!とするだけで、テスト、マージ、デプロイまで全て自動化してくれます。

自動化って男のロマンじゃないですか??

12
4
0

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
12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?