Getting started Circle CI 2.0

Circle CI 2.0入門

Circle CI 2.0で、DB連携した状態で実際にAPIをリクエストしてテストを実施するまでの流れ

環境

  • Node.js
  • Koa
  • Sequelize

用意するもの

  • Githubアカウント / Circle CIアカウント
  • ローカル環境でyarn test出来る状態の適当なAPIとテスト

Circle CI 2.0 概要

Jobs / Steps

  • Jobs and Steps - CircleCI
  • データのキャッシュ

    • Workspace: 1つのworkflow内でjob間のデータを保持する
    • cache: 同じjobが別のworkflowで実行されたとき用にデータを保持している
    • node_modulesとか
  • JobsはStepsの集合
  • 2.0ではmachine executorかdocker executorを選択できる

    • docker: キーをconfig.ymlで指定して、publicなdocker imageをJobs実行に利用できる
  • Stepsはジョブ内で実行されるコマンドの集合
  • Jobs / Stepsをまず定義して、WorkflowでJobsのオーケストレーションをする

Workflows

  • Orchestrating Workflows - CircleCI
  • Jobの集合とそれの実行順を管理している
  • Workflowsを設定しない場合、buildジョブの定義が必要
  • Workflowsはconfig.ymlの最後に workflows: キーを用意する

    • versionとジョブの指定を配下で行う
    • ジョブを直列で実行する場合は、 requires: を設定していく
    • requiresを複数設定すると待ち合わせっぽくもなる
  • 他にも設定できそうなこと

    • 手動でのapprove設定
    • スケジューリング
    • contextを利用してjob間で環境変数をシェア
    • ブランチ / タグ指定でのjob実行フィルタ

Circle CI設定

version: 2 # use CircleCI 2.0
jobs: # a collection of steps
  build: # runs not using Workflows must have a `build` job as entry point
    working_directory: ~/circleci-practice # directory where steps will run
    docker: # run the steps with Docker
      - image: circleci/node:8.11.1 # ...with this image as the primary container; this is where all `steps` will run
        environment:
          NODE_ENV: test
      - image: circleci/mysql:5.6 # and this image as the secondary service container
        environment:
          MYSQL_DATABASE: library
    steps: # a collection of executable commands 
      - checkout # special step to check out source code to working directory
      - restore_cache:
          name: Restore Yarn Package Cache
          keys:
            - yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
            - yarn-packages-{{ .Branch }}
            - yarn-packages-master
            - yarn-packages-
      - run:
          name: Install Dependencies
          command: yarn install
      - save_cache:
          name: Save Yarn Package Cache
          key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
          paths:
            - node_modules/
      - run:
          name: Wait for db setup and exec migration
          command: node wait-for-db.js ./node_modules/.bin/sequelize db:migrate
      - run:
          name: Setting app process and wait
          command: node ./src/app.js
          background: true
      - run:
          name: Sleep 15sec
          command: sleep 15
      - run:
          name: yarn test
          command: yarn test

解説

  • docker imagesの指定

    • nodeのイメージとmysqlのイメージを利用
    • 必要な環境変数を設定できる
    • mysqlイメージはデフォルトの環境変数があるので、上書きが必要なものを記述
    docker: # run the steps with Docker
      - image: circleci/node:8.11.1 # ...with this image as the primary container; this is where all `steps` will run
        environment:
          NODE_ENV: test
      - image: circleci/mysql:5.6 # and this image as the secondary service container
        environment:
          MYSQL_DATABASE: library
  • Circle CIが用意しているデフォルトのnode imagesでもyarnが使える

  • DBのセットアップ待ち

    • DBのセットアップを待ってアプリを起動する仕組みもdockerizeコマンドで対応できそう

    • 自分の場合はdocker-compose用に、sequelizeでwaitする仕組みを用意していたのでそれを利用

      • sequelize: Node.js用のORM
  • DBのセットアップ完了を待つcommand

      - run:
          name: Wait for db setup and exec migration
          command: node wait-for-db.js ./node_modules/.bin/sequelize db:migrate
  • wait-for-db.jsの中身

    • sequelizeで済ませて、mysqlクライアントをインストールしなくて済むようにしたかった
const { exec } = require("child_process");
const Sequelize = require("sequelize");

const sequelize = new Sequelize("library", "root", "", {
  host: process.env.NODE_ENV === "development" ? "mysql" : "127.0.0.1",
  dialect: "mysql",
  pool: {
    max: 5
  }
});

const command = process.argv.reduce((cmd, arg, i) => {
  if (i > 2) cmd = cmd + ` ${arg}`;
  return cmd;
}, process.argv[2]);

let count = 0;
const i = setInterval(() => {
  count++;
  if (count > 60) {
    clearInterval(i)
    return;
  }
  sequelize
    .authenticate()
    .then(() => {
      clearInterval(i);
      return exec(command, (err, stdout, stderr) => {
        if (err) {
          console.error(err);
          sequelize.close();
          return;
        }
        console.log(stdout);
        console.log(stderr);
        sequelize.close();
        return;
      });
    })
    .catch(() => {
      console.log("unreachable");
    });
}, 1000);
  • background

    • APIサーバーを起動しつつテスト実行する場合は、APIサーバー起動をバックグラウンドで行う
    • background: true を指定する
      - run:
          name: Setting app process and wait
          command: node ./src/app.js
          background: true
  • sleep

    • アプリのセットアップ完了を待つ必要があったので、sleepコマンドを利用
    • DBのセットアップ待ちもsleepでもいい説
      - run:
          name: Sleep 15sec
          command: sleep 15
      - run:
          name: yarn test
          command: yarn test

CIの開始

  • Circle CIのダッシュボードでリポジトリを選択してビルドを開始する

ほかにやりたいこと