AngularのプロジェクトをCircleCIで実行しようとしたらハマった話

# 要点
- stepsにnpm installを書く
- workflowsでrequiresするときは、ジョブ名の隣に":"をつける
- angularのtestを実行するときはbrowserありのdockerイメージを選ぶ
- testはwatchオプションをtrueにする

# 導入
CircleCIの導入は公式のドキュメントを見て実施。
https://circleci.com/docs/ja/2.0/getting-started/
リポジトリのルートに".circleci"ディレクトリを置いて、その中にconfig.ymlを入れる。
nodeのdockerイメージは
https://circleci.com/docs/2.0/circleci-images/#nodejs
https://circleci.com/docs/2.0/docker-image-tags.json
を見て、今使っているnodeのバージョン(10.15.3)を探した。

# stepsにnpm installを書く

```config.yml
version: 2
jobs:
  build:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3 # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: npm run build
```

こんなconfigで実行したら

```
#!/bin/bash -eo pipefail
npm run build

> sgweb@0.0.0 build /home/circleci/project
> ng build

sh: 1: ng: not found
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! sgweb@0.0.0 build: `ng build`
npm ERR! spawn ENOENT
npm ERR! 
npm ERR! Failed at the sgweb@0.0.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm WARN Local package.json exists, but node_modules missing, did you mean to install?

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/circleci/.npm/_logs/2019-05-05T15_44_54_706Z-debug.log
Exited with code 1
```

ng not foundと怒られた。勝手にnpm installはしてくれないので自分で指定する必要がある。
以下のように修正。

```config.yml
version: 2
jobs:
  build:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3 # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: npm install
      - run: npm run build
```

# workflowsでrequiresするときは、ジョブ名の隣に":"をつける

workflowsでジョブの実行順序指定しようとconfig.ymlを修正。

```config.yml
version: 2
jobs:
  build:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3 # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: npm install
      - run: npm run build
  lint:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3 # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: npm install
      - run: npm run lint
  test:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3 # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: npm install
      - run: npm test
workflows:
  version: 2
  build_and_lint_and_test:
    jobs: 
      - build
      - lint
        requires:
          - build
      - test
        requires:
          - lint
```

こんなconfigで実行したら

```
#!/bin/sh -eo pipefail
# Unable to parse YAML
# mapping values are not allowed here
#  in 'string', line 30, column 19:
#               requires:
#                       ^
# 
# -------
# Warning: This configuration was auto-generated to show you the message above.
# Don't rerun this job. Rerunning will have no effect.
false

Exited with code 1
```

パースできないと怒られる。
https://circleci.com/docs/ja/2.0/workflows/#シーケンシャルジョブの例
のconfig.ymlとにらめっこして、ジョブ名の隣に":"が必要なことに気づく。

```config.yml
version: 2
jobs:
  build:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3 # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: npm install
      - run: npm run build
  lint:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3 # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: npm install
      - run: npm run lint
  test:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3 # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: npm install
      - run: npm test
workflows:
  version: 2
  build_and_lint_and_test:
    jobs: 
      - build
      - lint: ### ここ
        requires:
          - build
      - test: ### ここ
        requires:
          - lint
```

# angularのtestを実行するときはbrowserありのdockerイメージを選ぶ

ng testするときはウェブブラウザが必要だが、バージョン名だけのdockerイメージだとウェブブラウザがない。
ウェブブラウザ付きのdockerイメージを選ぶ。
ウェブブラウザなしのdockerイメージだとこんなふうに怒られる。

```
（中略）
05 05 2019 16:26:43.381:INFO [karma-server]: Karma v4.0.1 server started at http://0.0.0.0:9876/
05 05 2019 16:26:43.381:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
05 05 2019 16:26:43.388:INFO [launcher]: Starting browser Chrome
05 05 2019 16:26:43.389:ERROR [launcher]: No binary for Chrome browser on your platform.
  Please, set "CHROME_BIN" env variable.
（中略）
```

なのでconfig.ymlを以下のように修正する。

```config.yml
jobs:
  build:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3-browsers # the primary container, where your job's commands are run
```

# testはwatchオプションをtrueにする

無事testは実行できたが、いつまで経っても終わらない。
ng testはオプション無しで起動すると、コードの変更を検知して動くように動作するためいつまでも動き続ける。
一回だけ実行するようにするには watch オプションをfalseにする。（angular バージョン7の場合。）
（npmスクリプトにオプションを渡すときは、"--watch=false"の手前に更に"--"が必要）

```config.yml
version: 2
jobs:
  build:
    docker: # use the docker executor type; machine and macos executors are also supported
      - image: circleci/node:10.15.3-browsers # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: npm install
      - run: npm run build
      - run: npm run lint
      - run: npm test -- --watch=false ### ここ
```