LoginSignup
13
2

More than 3 years have passed since last update.

自作ライブラリの運用で代わり果ててしまった CircleCI の設定ファイル

Posted at

QiitaTrend という Ruby の gem を開発していく中で導入した CircleCI の設定がどういう理由でどう変わっていったのか当時の状況を思い出しつつまとめてみたいと思います

qiita_trend

QiitaTrend は Qiitaのトレンド情報(Daily、Weekly、Monthly)を10秒で取得することができる gem になります。

config.yml の大まかな年表

CircleCI の config.yml を今まででたくさん更新してきました。
運用してきた config.yml は厳密にはもっと修正が細かいですが大まかに分けると以下のような修正履歴になります。

年月 変更内容
2019/08 CircleCIの導入
2019/08 YARD でドキュメントが自動生成されるように変更
2019/08 ワークフローを導入
2019/12 CircleCI2.1へバージョンアップ
2020/02 workspace 機能の導入
2020/04 slack 通知・デプロイ承認機能追加
2020/08 毎日テストを実行させるワークフローを追加
2020/10 CircleCI のイメージを次世代のものに変更
2020/11 Ruby の orb の導入

2019年8月:初じめてのCircleCI

自分の勉強のために Ruby の gem を作成しようというところから始まります。

テストとデプロイを自動化したい という思いから業務でも使用していた CircleCI を導入すること にしました。
そもそもこの時点では CI/CDの構築を一回もしたことがなく ほぼ知識がない状態からの導入です。

導入方法

そもそも知識がない状態でどうやって導入したんだっけ?
思い出してみると初導入に関しては Qiita に記事 として残してあります。

基本的には 公式のドキュメントを読んでそのままコピペしたものに不必要なものを削除、必要な機能を追加していき作成 しました。詳しくは Qiita の記事を読んでください。

config.yml

初めて導入した config.yml は以下です。今、見るととても簡素なものですね(笑)
version2.1 ではないし、workflow も組んでいませんね。

00_add_first_circleci


config.yml
# Ruby CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
#
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      - image: circleci/ruby:2.6.0-node-browsers
        environment:
          BUNDLER_VERSION: 2.0.1

      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/postgres:9.4

    working_directory: ~/repo

    steps:
      - checkout
      # Download and cache dependencies
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-
      # install Bundler!
      # ref:https://discuss.circleci.com/t/using-bundler-2-0-during-ci-fails/27411
      - run:
          name: install bundler
          command: |
            sudo gem update --system
            sudo gem uninstall bundler
            sudo rm /usr/local/bin/bundle
            sudo rm /usr/local/bin/bundler
            sudo gem install bundler
      # install gem!
      - run:
          name: install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}
      # run rubocop!
      - run:
          name: run rubocop
          command: |
            bundle exec rubocop
      # run tests!
      - run:
          name: run tests
          command: |
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out test_results/rspec.xml \
              --format progress \
              $TEST_FILES
      # collect reports
      - store_test_results:
          path: test_results
      - store_artifacts:
          # テスト結果をtest-resultsディレクトリに吐き出す
          path: test_results
          destination: test-results
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results
      # deploy RubyGems
      - deploy:
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              mkdir ~/.gem
              curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
              git config user.name dodonki1223
              git config user.email $RUBYGEMS_EMAIL
              bundle exec rake build
              bundle exec rake release
            fi


追加した内容

キャッシュ以外の処理について説明します。基本的には CircleCI のドキュメントに載っていたものをそのまま持ってきただけのものが多いです。

Bundler のインストール

  • Bundler のインストールを行っている処理
  • こちらは CircleCI のドキュメントに書かれていたものをコピペして実装
  • ちなみに Bundler とは gem のバージョンや gem の依存関係を管理してくれる gem のこと
- run:
    name: install bundler
    command: |
      sudo gem update --system
      sudo gem uninstall bundler
      sudo rm /usr/local/bin/bundle
      sudo rm /usr/local/bin/bundler
      sudo gem install bundler

依存関係のインストール

  • gem で使用する依存関係をインストールする処理
  • こちらも CircleCI のドキュメントに書かれていたものをコピペして実装
- run:
    name: install gem
    command: |
      # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
      bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3

RuboCop の実行

  • 静的解析ツールの RuboCop を実行している処理
- run:
    name: run rubocop
    command: |
      bundle exec rubocop

RSpec の実行

  • RSpec を実行している処理(テストの実行)
  • こちらも CircleCI のドキュメントに書かれていたものをコピペして実装
- run:
    name: run tests
    command: |
      TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
      bundle exec rspec \
        --format progress \
        --format RspecJunitFormatter \
        --out test_results/rspec.xml \
        --format progress \
        $TEST_FILES

成果物のアップロード

  • テスト結果、カバレッジの結果を CircleCI にアップロードして結果を見れるようにしている処理
  • こちらも CircleCI のドキュメントを参考に実装したものです
# collect reports
- store_test_results:
    path: test_results
- store_artifacts:
    # テスト結果をtest-resultsディレクトリに吐き出す
    path: test_results
    destination: test-results
- store_artifacts:
    # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
    path: coverage
    destination: coverage-results

RubyGems へデプロイ

- deploy:
    command: |
      if [ "${CIRCLE_BRANCH}" == "master" ]; then
        mkdir ~/.gem
        curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
        git config user.name dodonki1223
        git config user.email $RUBYGEMS_EMAIL
        bundle exec rake build
        bundle exec rake release
      fi

初めて導入してみてどうだったか?

  • CI/CD がよくわからない難しいものだと思っていたが実際に順を追って導入すると そんなに難しくないこと がわかった
  • CircleCI の キャッシュについてある程度、理解することができた

2019年8月:ドキュメントの自動作成

gem のドキュメントを RubyDoc.info に公開するために YARD を導入しドキュメントを自動生成する処理を追加。 実際に公開しているドキュメントはこちらになります。

config.yml

ドキュメントを自動生成する処理を追加した config.yml です。

01_add_create_document


config.yml
# Ruby CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
#
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      - image: circleci/ruby:2.6.0-node-browsers
        environment:
          BUNDLER_VERSION: 2.0.1

      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/postgres:9.4

    working_directory: ~/repo

    steps:
      - checkout

      # Download and cache dependencies
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

      # install Bundler!
      # ref:https://discuss.circleci.com/t/using-bundler-2-0-during-ci-fails/27411
      - run:
          name: install bundler
          command: |
            sudo gem update --system
            sudo gem uninstall bundler
            sudo rm /usr/local/bin/bundle
            sudo rm /usr/local/bin/bundler
            sudo gem install bundler
      # install gem!
      - run:
          name: install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}
      # run rubocop!
      - run:
          name: run rubocop
          command: |
            bundle exec rubocop
      # run tests!
      - run:
          name: run tests
          command: |
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out test_results/rspec.xml \
              --format progress \
              $TEST_FILES
      # create document
      - run:
          name: create document
          command: |
            bundle exec yard
      # collect reports
      - store_test_results:
          path: test_results
      - store_artifacts:
          # テスト結果をtest-resultsディレクトリに吐き出す
          path: test_results
          destination: test-results
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results
      - store_artifacts:
          # ドキュメントの結果をyard-resultsディレクトリに吐き出す
          path: ./doc
          destination: yard-results
      # deploy RubyGems
      - deploy:
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              mkdir ~/.gem
              curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
              git config user.name dodonki1223
              git config user.email $RUBYGEMS_EMAIL
              bundle exec rake build
              bundle exec rake release
            fi


更新内容

YARD の作成処理と作成した YARD のアップロード機能を追加。

YARD の作成

  • YARD のドキュメントを参考に実装
# create document
- run:
    name: create document
    command: |
      bundle exec yard

作成した YARD のアップロード

  • 以前同じようなことをしているので特に何も考えなくても実装できた
- store_artifacts:
    # ドキュメントの結果をyard-resultsディレクトリに吐き出す
    path: ./doc
    destination: yard-results

2019年8月:ワークフローの導入

ワークフローという機能があることに気づき、 ワークフローの導入を行う

config.yml

ワークフローの設定を追加した config.yml です。

02_add_workflows


config.yml
# Ruby CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
#
version: 2
jobs:
  build:
    docker:
      - image: circleci/ruby:2.6.0
        environment:
          BUNDLE_PATH: vendor/bundle

    working_directory: ~/repo

    steps:
      - checkout

      # Install Bundler
      # ref:https://discuss.circleci.com/t/using-bundler-2-0-during-ci-fails/27411
      - run:
          name: Install Bundler
          command: |
            echo 'export BUNDLER_VERSION=$(cat Gemfile.lock | tail -1 | tr -d " ")' >> $BASH_ENV
            source $BASH_ENV
            gem install bundler

      # Which version of bundler?
      - run:
          name: Which bundler?
          command: bundle -v

      # Restore bundle cache
      # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

      # Install gem
      - run:
          name: Install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3

      # Store bundle cache for Ruby dependencies
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

      # Run RuboCop
      - run:
          name: Run RuboCop
          command: |
            bundle exec rubocop

      # Run tests
      - run:
          name: Run tests
          command: |
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out test_results/rspec.xml \
              --format progress \
              $TEST_FILES

      # Create document
      - run:
          name: Create document
          command: |
            bundle exec yard

      # Collect Reports
      - store_test_results:
          path: test_results
      - store_artifacts:
          # テスト結果をtest-resultsディレクトリに吐き出す
          path: test_results
          destination: test-results
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results
      - store_artifacts:
          # ドキュメントの結果をyard-resultsディレクトリに吐き出す
          path: ./doc
          destination: yard-results

  deploy:
    docker:
      - image: circleci/ruby:2.6.0

    steps:
      - checkout

      # Install Bundler
      # ref:https://discuss.circleci.com/t/using-bundler-2-0-during-ci-fails/27411
      - run:
          name: install Bundler
          command: |
            echo 'export BUNDLER_VERSION=$(cat Gemfile.lock | tail -1 | tr -d " ")' >> $BASH_ENV
            source $BASH_ENV
            gem install bundler

      # Which version of bundler?
      - run:
          name: Which bundler?
          command: bundle -v

      # Restore bundle cache
      # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            - v1-dependencies-

      # Install gem
      - run:
          name: Install gem
          command: bundle check --path vendor/bundle || bundle install

      # Store bundle cache for Ruby dependencies
      - save_cache:
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

      # Deploy RubyGems
      - run:
          name: Deploy RubyGems
          command: |
            curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
            git config user.name dodonki1223
            git config user.email $RUBYGEMS_EMAIL
            bundle exec rake build
            bundle exec rake release

workflows:
  version: 2
  build-and-deploy:
    jobs:
      - build
      - deploy:
          requires:
            - build
          filters:
            branches:
              only: master # masterブランチの時だけDeployJobを実行するようにする


更新内容

build の一部を切り離し deploy という job を作成しそれぞれを workflows で順番を担保させるように改修。

追加した workflow 設定

  • build → deploy の順番で処理されるように設定
  • deploy は master ブランチのみ実行されるように設定。
workflows:
  version: 2
  build-and-deploy:
    jobs:
      - build
      - deploy:
          requires:
            - build
          filters:
            branches:
              only: master # masterブランチの時だけDeployJobを実行するようにする

2019年12月:CircleCI 2.1 の導入

CircleCI のバージョンを 2.0 から 2.1 に変更し冗長な書きぶりを排除
この改修をしてた時は AWS 認定 ソリューションアーキテクト – アソシエイト を受けて落ちてやけくそになっていた時でした(笑)
これが完成した時は少しだけいい気分になりました……。CircleCI のおかげです。

AWS 認定 ソリューションアーキテクト – アソシエイト は1ヶ月後に無事受かりました。

config.yml

バージョンを 2.0 から 2.1 に変更した config.yml です。

03_update_version2_1


config.yml
version: 2.1
executors:
  base:
    docker:
      - image: circleci/ruby:2.6.0
        environment:
          BUNDLE_PATH: vendor/bundle
    working_directory: ~/repo

commands:
  # ref:https://discuss.circleci.com/t/using-bundler-2-0-during-ci-fails/27411
  install-bundler:
    steps:

      - run:
          name: Install Bundler
          command: |
            echo 'export BUNDLER_VERSION=$(cat Gemfile.lock | tail -1 | tr -d " ")' >> $BASH_ENV
            source $BASH_ENV
            gem install bundler
            # Which version of bundler?
            bundle -v

  # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
  restore-gem-cache:
    steps:

      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

  install-gem:
    steps:
      - run:
          name: Install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3

  save-gem-cache:
    steps:
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

  run-rubocop:
    steps:
      - run:
          name: Run RuboCop
          command: |
            bundle exec rubocop

  run-tests:
    steps:
      - run:
          name: Run tests
          command: |
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out test_results/rspec.xml \
              --format progress \
              $TEST_FILES

  create-document:
    steps:
      - run:
          name: Create document
          command: |
            bundle exec yard

  collect-reports:
    steps:
      # ref:https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results
      - store_test_results:
          path: test_results
      - store_artifacts:
          # テスト結果をtest-resultsディレクトリに吐き出す
          path: test_results
          destination: test-results
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results
      - store_artifacts:
          # ドキュメントの結果をyard-resultsディレクトリに吐き出す
          path: ./doc
          destination: yard-results

  # Deploy RubyGems
  deploy-rubygems:

    steps:
      - run:
          name: Deploy RubyGems
          command: |
            curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
            git config user.name dodonki1223
            git config user.email $RUBYGEMS_EMAIL
            bundle exec rake build
            bundle exec rake release

jobs:
  setup:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - install-gem
      - save-gem-cache

  lint:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - run-rubocop

  test:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - run-tests
      - create-document
      - collect-reports

  deploy:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - deploy-rubygems

workflows:
  version: 2.1
  main:
    jobs:
      - setup
      - lint:
          requires:
            - setup
      - test:
          requires:
            - setup
      - deploy:
          requires:
            - lint
            - test
          filters:
            branches:
              only: master # masterブランチの時だけDeployJobを実行するようにする


更新内容

この時の改修が一番変更箇所が多くて中身がガラッと変わった時です。
executorcommand 機能を使用することで冗長な部分がなくなりかなりスッキリとした改修になりました。

まだ 2.0 を使っているなら はやく 2.1 にバージョンアップすることをオススメ します。

executors

  • executors を使用しそれぞれの job で image を使い回すことができるようになった
executors:
  base:
    docker:
      - image: circleci/ruby:2.6.0
        environment:
          BUNDLE_PATH: vendor/bundle
    working_directory: ~/repo

commands

  • commands に必要な処理をそれぞれ実装し使い回せるようにする
commands:
  # ref:https://discuss.circleci.com/t/using-bundler-2-0-during-ci-fails/27411
  install-bundler:
    steps:

      - run:
          name: Install Bundler
          command: |
            echo 'export BUNDLER_VERSION=$(cat Gemfile.lock | tail -1 | tr -d " ")' >> $BASH_ENV
            source $BASH_ENV
            gem install bundler
            # Which version of bundler?
            bundle -v

  # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
  restore-gem-cache:
    steps:

      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

  install-gem:
    steps:
      - run:
          name: Install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3

  save-gem-cache:
    steps:
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

  run-rubocop:
    steps:
      - run:
          name: Run RuboCop
          command: |
            bundle exec rubocop

  run-tests:
    steps:
      - run:
          name: Run tests
          command: |
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out test_results/rspec.xml \
              --format progress \
              $TEST_FILES

  create-document:
    steps:
      - run:
          name: Create document
          command: |
            bundle exec yard

  collect-reports:
    steps:
      # ref:https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results
      - store_test_results:
          path: test_results
      - store_artifacts:
          # テスト結果をtest-resultsディレクトリに吐き出す
          path: test_results
          destination: test-results
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results
      - store_artifacts:
          # ドキュメントの結果をyard-resultsディレクトリに吐き出す
          path: ./doc
          destination: yard-results

  # Deploy RubyGems
  deploy-rubygems:
    steps:
      - run:
          name: Deploy RubyGems
          command: |
            curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
            git config user.name dodonki1223
            git config user.email $RUBYGEMS_EMAIL
            bundle exec rake build
            bundle exec rake release

jobs

  • executor と command を使用し jobs をスッキリと記述
  • 細かい単位で job を定義する
jobs:
  setup:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - install-gem
      - save-gem-cache

  lint:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - run-rubocop

  test:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - run-tests
      - create-document
      - collect-reports

  deploy:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - deploy-rubygems

workflows

  • 細かくした job を反映させる
workflows:
  version: 2.1
  main:
    jobs:
      - setup
      - lint:
          requires:
            - setup
      - test:
          requires:
            - setup
      - deploy:
          requires:
            - lint
            - test
          filters:
            branches:
              only: master # masterブランチの時だけDeployJobを実行するようにする

2020年2月:workspace 機能の導入

workspace という job 間で使用できるキャッシュ機能 を知り、実装する

config.yml

workspace を追加し job 間でキャッシュを使えるようにした config.yml です。

04_add_workspace


config.yml
version: 2.1
executors:
  base:
    docker:
      - image: circleci/ruby:2.6.0
        environment:
          # Bundlerのパス設定が書き換えられ`vendor/bundle`ではなくて`/usr/local/bundle`を参照してしまい`bundle exec`でエラーになる
          # Bundlerのconfigファイル(pathの設定がされたもの)をworkspaceで永続化し`vendor/bundle`を参照するようにするための設定
          BUNDLE_APP_CONFIG: .bundle
    working_directory: ~/dodonki1223/qiita_trend

commands:
  install-bundler:
    steps:
      - run:
          name: Install bundler(2.1.0)
          command: gem install bundler:2.1.0

  # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
  restore-gem-cache:
    steps:
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

  install-gem:
    steps:
      - run:
          name: Install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3

  save-gem-cache:
    steps:
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

  save-workspace:
    steps:
      - persist_to_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          root: .
          paths: .

  using-workspace:
    steps:
      - attach_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          at: .

  run-rubocop:
    steps:
      - run:
          name: Run RuboCop
          command: |
            bundle exec rubocop

  run-tests:
    steps:
      - run:
          name: Run tests
          command: |
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out test_results/rspec.xml \
              --format progress \
              $TEST_FILES

  create-document:
    steps:
      - run:
          name: Create document
          command: |
            bundle exec yard

  collect-reports:
    steps:
      # ref:https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results
      - store_test_results:
          path: test_results
      - store_artifacts:
          # テスト結果をtest-resultsディレクトリに吐き出す
          path: test_results
          destination: test-results
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results
      - store_artifacts:
          # ドキュメントの結果をyard-resultsディレクトリに吐き出す
          path: ./doc
          destination: yard-results

  deploy-rubygems:
    steps:
      # ref:https://support.circleci.com/hc/ja/articles/115015628247-%E6%8E%A5%E7%B6%9A%E3%82%92%E7%B6%9A%E8%A1%8C%E3%81%97%E3%81%BE%E3%81%99%E3%81%8B-%E3%81%AF%E3%81%84-%E3%81%84%E3%81%84%E3%81%88-
      # read/write両方の権限が必要
      - add_ssh_keys:
          fingerprints:
            - "38:d2:72:5e:9f:67:93:9a:ec:95:94:a2:0e:bf:41:9e"

      # ref:https://circleci.com/docs/2.0/gh-bb-integration/#establishing-the-authenticity-of-an-ssh-host
      - run:
          name: Avoid hosts unknown for github
          command: |
            mkdir -p ~/.ssh
            echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
                  bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
                  ' >> ~/.ssh/known_hosts

      - run:
          name: Deploy RubyGems
          command: |
            curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials
            chmod 0600 ~/.gem/credentials
            git config user.name dodonki1223
            git config user.email $RUBYGEMS_EMAIL
            bundle exec rake build
            bundle exec rake release

jobs:
  setup:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - install-gem
      - save-gem-cache
      - save-workspace

  lint:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-rubocop

  test:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-tests
      - create-document
      - collect-reports

  deploy:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - deploy-rubygems

workflows:
  version: 2.1
  main:
    jobs:
      - setup
      - lint:
          requires:
            - setup
      - test:
          requires:
            - setup
      - deploy:
          requires:
            - lint
            - test
          filters:
            branches:
              only: master # masterブランチの時だけDeployJobを実行するようにする


更新内容

workspace の保存と適用の command を追加しそれを job で使用するように更新。

workspace の保存と適用の command を追加

command に workspace の保存と適用のコマンドをそれぞれ追加する。

save-workspace:
  steps:
    - persist_to_workspace:
        # working_directory からの相対パスか絶対パスを指定します
        root: .
        paths: .

using-workspace:
  steps:
    - attach_workspace:
        # working_directory からの相対パスか絶対パスを指定します
        at: .

job で workspace を使用する

  • setup の job で workspace に保存する
  • setup で作成した資材をそれぞれの job で使用する
jobs:
  setup:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - install-gem
      - save-gem-cache
      - save-workspace

  lint:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-rubocop

  test:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-tests
      - create-document
      - collect-reports

  deploy:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - deploy-rubygems

workspace の導入でわかったこと

caching-dependencies-overview

画像は CircleCIのドキュメント より参照

  • CircleCI で使用できるキャッシュについて理解できた
  • job のキャッシュworkflow で使い回せるキャッシュ(workspace) があることを知った

2020年4月:Slack通知・デプロイ承認機能の追加

初めて orb を導入し slack 通知とデプロイの承認機能を追加。

config.yml

slack 通知とデプロイの承認機能を追加した config.yml です。

05_slack_notify


config.yml
version: 2.1
orbs:
  slack: circleci/slack@3.4.2
executors:
  base:
    docker:
      - image: circleci/ruby:2.6.0
        environment:
          # Bundlerのパス設定が書き換えられ`vendor/bundle`ではなくて`/usr/local/bundle`を参照してしまい`bundle exec`でエラーになる
          # Bundlerのconfigファイル(pathの設定がされたもの)をworkspaceで永続化し`vendor/bundle`を参照するようにするための設定
          BUNDLE_APP_CONFIG: .bundle
    working_directory: ~/dodonki1223/qiita_trend

commands:
  install-bundler:
    steps:
      - run:
          name: Install bundler(2.1.0)
          command: gem install bundler:2.1.0

  # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
  restore-gem-cache:
    steps:
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

  install-gem:
    steps:
      - run:
          name: Install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3

  save-gem-cache:
    steps:
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

  save-workspace:
    steps:
      - persist_to_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          root: .
          paths: .

  using-workspace:
    steps:
      - attach_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          at: .

  run-rubocop:
    steps:
      - run:
          name: Run RuboCop
          command: |
            bundle exec rubocop

  run-tests:
    steps:
      - run:
          name: Run tests
          command: |
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out test_results/rspec.xml \
              --format progress \
              $TEST_FILES

  collect-reports:
    steps:
      # ref:https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results
      - store_test_results:
          path: test_results
      - store_artifacts:
          # テスト結果をtest-resultsディレクトリに吐き出す
          path: test_results
          destination: test-results
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results

  create-document:
    steps:
      - run:
          name: Create document
          command: |
            bundle exec yard
      - store_artifacts:
          # ドキュメントの結果をyard-resultsディレクトリに吐き出す
          path: ./doc
          destination: yard-results

  deploy-rubygems:
    steps:
      # ref:https://support.circleci.com/hc/ja/articles/115015628247-%E6%8E%A5%E7%B6%9A%E3%82%92%E7%B6%9A%E8%A1%8C%E3%81%97%E3%81%BE%E3%81%99%E3%81%8B-%E3%81%AF%E3%81%84-%E3%81%84%E3%81%84%E3%81%88-
      # read/write両方の権限が必要
      - add_ssh_keys:
          fingerprints:
            - "38:d2:72:5e:9f:67:93:9a:ec:95:94:a2:0e:bf:41:9e"

      # ref:https://circleci.com/docs/2.0/gh-bb-integration/#establishing-the-authenticity-of-an-ssh-host
      - run:
          name: Avoid hosts unknown for github
          command: |
            mkdir -p ~/.ssh
            echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
                  bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
                  ' >> ~/.ssh/known_hosts

      - run:
          name: Deploy RubyGems
          command: |
            curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials
            chmod 0600 ~/.gem/credentials
            git config user.name dodonki1223
            git config user.email $RUBYGEMS_EMAIL
            bundle exec rake build
            bundle exec rake release

  deploy-notification:
    steps:
      - slack/status:
          success_message: ':circleci-pass: RubyGemsにデプロイが完了しました\n:github_octocat: User: $CIRCLE_USERNAME'
          failure_message: ':circleci-fail: RubyGemsにデプロイが失敗しました\n:github_octocat: User: $CIRCLE_USERNAME'

jobs:
  setup:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - install-gem
      - save-gem-cache
      - save-workspace

  lint:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-rubocop

  test:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-tests
      - collect-reports

  document:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - create-document

  deploy:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - deploy-rubygems
      - deploy-notification

workflows:
  version: 2.1
  main:
    jobs:
      - setup
      - lint:
          requires:
            - setup
      - test:
          requires:
            - setup
      - document:
          requires:
            - setup
      - slack/approval-notification:
          message: ':circleci-pass: RubyGemsへのデプロイ準備が整っています\n:github_octocat: User: $CIRCLE_USERNAME\nデプロイを実行する場合は *Approve* を押してください'
          requires:
            - lint
            - test
          filters:
            branches:
              only: master
      - approval-job:
          type: approval
          requires:
            - slack/approval-notification
      - deploy:
          requires:
            - approval-job
          filters:
            branches:
              only: master


更新内容

orbs に slack を追加し承認のプロセスを slack に通知したり、デプロイ完了後に slack に通知させる機能を追加した。

05_01_slack_notify_sample

orbs に slack を追加

version: 2.1
orbs:
  slack: circleci/slack@3.4.2

デプロイ完了通知を追加

  • command にデプロイの完了を slack に通知させる
deploy-notification:
  steps:
    - slack/status:
        success_message: ':circleci-pass: RubyGemsにデプロイが完了しました\n:github_octocat: User: $CIRCLE_USERNAME'
        failure_message: ':circleci-fail: RubyGemsにデプロイが失敗しました\n:github_octocat: User: $CIRCLE_USERNAME'
  • deploy の job の最後に slack 通知を追加
deploy:
  executor: base
  steps:
    - using-workspace
    - install-bundler
    - deploy-rubygems
    - deploy-notification

承認プロセスを追加

  • workflow に承認のプロセスを追加
  • master ブランチの時のみ実行されるようにする
workflows:
  version: 2.1
  main:
    jobs:
      
      
      
      - slack/approval-notification:
          message: ':circleci-pass: RubyGemsへのデプロイ準備が整っています\n:github_octocat: User: $CIRCLE_USERNAME\nデプロイを実行する場合は *Approve* を押してください'
          requires:
            - lint
            - test
          filters:
            branches:
              only: master
      
      
      

2020年8月:毎日テストを実行させるワークフローを追加

QiitaTrend という gem は Qiita のサイトをスクレイピングしているため、DOM の構成が変わるとエラーで落ちてしまいます。
いつの間にかテストが落ちていることが何度かあり gem が使用できなくなることがあった。
DOM の構成が変わったことをいち早く検知 する必要があったため 毎日テストを実行する ように修正。

config.yml

テストが定期実行するように設定を追加した config.yml です。

06_triggered_execute


config.yml
version: 2.1
orbs:
  slack: circleci/slack@3.4.2
executors:
  base:
    docker:
      - image: circleci/ruby:2.6.0
        auth:
          username: dodonki1223
          password: $DOCKERHUB_PASSWORD
        environment:
          # Bundlerのパス設定が書き換えられ`vendor/bundle`ではなくて`/usr/local/bundle`を参照してしまい`bundle exec`でエラーになる
          # Bundlerのconfigファイル(pathの設定がされたもの)をworkspaceで永続化し`vendor/bundle`を参照するようにするための設定
          BUNDLE_APP_CONFIG: .bundle
          # ref: https://circleci.com/docs/2.0/faq/#how-can-i-set-the-timezone-in-docker-images
          TZ: "Asia/Tokyo"
    working_directory: ~/dodonki1223/qiita_trend

commands:
  install-bundler:
    steps:
      - run:
          name: Install bundler(2.1.0)
          command: gem install bundler:2.1.0

  # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
  restore-gem-cache:
    steps:
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

  install-gem:
    steps:
      - run:
          name: Install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3

  save-gem-cache:
    steps:
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

  save-workspace:
    steps:
      - persist_to_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          root: .
          paths: .

  using-workspace:
    steps:
      - attach_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          at: .

  run-rubocop:
    steps:
      - run:
          name: Run RuboCop
          command: |
            bundle exec rubocop

  run-tests:
    steps:
      - run:
          name: Run tests
          command: |
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out test_results/rspec/rspec.xml \
              --format progress \
              $TEST_FILES

  collect-reports:
    steps:
      # ref:https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results
      - store_test_results:
          path: test_results
      - store_artifacts:
          # テスト結果をtest-resultsディレクトリに吐き出す
          path: test_results
          destination: test-results
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results

  create-document:
    steps:
      - run:
          name: Create document
          command: |
            bundle exec yard
      - store_artifacts:
          # ドキュメントの結果をyard-resultsディレクトリに吐き出す
          path: ./doc
          destination: yard-results

  deploy-rubygems:
    steps:
      # ref:https://support.circleci.com/hc/ja/articles/115015628247-%E6%8E%A5%E7%B6%9A%E3%82%92%E7%B6%9A%E8%A1%8C%E3%81%97%E3%81%BE%E3%81%99%E3%81%8B-%E3%81%AF%E3%81%84-%E3%81%84%E3%81%84%E3%81%88-
      # read/write両方の権限が必要
      - add_ssh_keys:
          fingerprints:
            - "38:d2:72:5e:9f:67:93:9a:ec:95:94:a2:0e:bf:41:9e"

      # ref:https://circleci.com/docs/2.0/gh-bb-integration/#establishing-the-authenticity-of-an-ssh-host
      - run:
          name: Avoid hosts unknown for github
          command: |
            mkdir -p ~/.ssh
            echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
                  bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
                  ' >> ~/.ssh/known_hosts

      - run:
          name: Deploy RubyGems
          command: |
            curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials
            chmod 0600 ~/.gem/credentials
            git config user.name dodonki1223
            git config user.email $RUBYGEMS_EMAIL
            bundle exec rake build
            bundle exec rake release

  deploy-notification:
    steps:
      - slack/status:
          success_message: ':circleci-pass: RubyGemsにデプロイが完了しました\n:github_octocat: User: $CIRCLE_USERNAME'
          failure_message: ':circleci-fail: RubyGemsにデプロイが失敗しました\n:github_octocat: User: $CIRCLE_USERNAME'

jobs:
  setup:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - install-gem
      - save-gem-cache
      - save-workspace

  lint:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-rubocop

  test:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-tests
      - collect-reports

  document:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - create-document

  deploy:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - deploy-rubygems
      - deploy-notification

workflows:
  version: 2.1
  main:
    jobs:
      - setup
      - lint:
          requires:
            - setup
      - test:
          requires:
            - setup
      - document:
          requires:
            - setup
      - slack/approval-notification:
          message: ':circleci-pass: RubyGemsへのデプロイ準備が整っています\n:github_octocat: User: $CIRCLE_USERNAME\nデプロイを実行する場合は *Approve* を押してください'
          requires:
            - lint
            - test
          filters:
            branches:
              only: master
      - approval-job:
          type: approval
          requires:
            - slack/approval-notification
      - deploy:
          requires:
            - approval-job
          filters:
            branches:
              only: master
  # 定期でテストを実行する
  # ref:https://circleci.com/docs/ja/2.0/triggers/
  nightly:
    triggers:
      - schedule:
          cron: "0 22 * * *" # UTCで記述
          filters:
            branches:
              only:
                - master
    jobs:
      - setup
      - test:
          requires:
            - setup


更新内容

RSpec を毎日実行しテストが落ちない限りは Qiita のトレンド情報を取得できることを担保する。

テストを毎日実行させる

  • triggers を使用し毎日、朝の7時にテストが実行されるようにする
workflows:
  version: 2.1
  # 定期でテストを実行する
  # ref:https://circleci.com/docs/ja/2.0/triggers/
  nightly:
    triggers:
      - schedule:
          cron: "0 22 * * *" # UTCで記述
          filters:
            branches:
              only:
                - master
    jobs:
      - setup
      - test:
          requires:
            - setup

毎日実行するようになってどうなった?

  • テストが何度か落ちて、DOMの構成が変わったことをいち早く検知することができるようになった
  • テストが落ちた時は CircleCI と slack を連携させているため通知が来てすぐに検知が可能

06_01_error_sample

こんな感じでエラーが slack に通知される

2020年10月:CircleCI のイメージを次世代ものに変更

CircleCI実践入門──CI/CDがもたらす開発速度と品質の両立 の本が発売されたので読んでみると cimg という次世代の image があることを知り、こちらを導入することにした。

config.yml

cimg に変更した config.yml

07_change_cimg


config.yml
version: 2.1
orbs:
  slack: circleci/slack@3.4.2
executors:
  base:
    docker:
      - image: cimg/ruby:2.6.6
        auth:
          username: dodonki1223
          password: $DOCKERHUB_PASSWORD
        environment:
          # Bundlerのパス設定が書き換えられ`vendor/bundle`ではなくて`/usr/local/bundle`を参照してしまい`bundle exec`でエラーになる
          # Bundlerのconfigファイル(pathの設定がされたもの)をworkspaceで永続化し`vendor/bundle`を参照するようにするための設定
          BUNDLE_APP_CONFIG: .bundle
          # ref: https://circleci.com/docs/2.0/faq/#how-can-i-set-the-timezone-in-docker-images
          TZ: "Asia/Tokyo"
    working_directory: ~/dodonki1223/qiita_trend

commands:
  install-bundler:
    steps:
      - run:
          name: Install bundler(2.1.0)
          command: gem install bundler:2.1.0

  # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
  restore-gem-cache:
    steps:
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

  install-gem:
    steps:
      - run:
          name: Install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3

  save-gem-cache:
    steps:
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

  save-workspace:
    steps:
      - persist_to_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          root: .
          paths: .

  using-workspace:
    steps:
      - attach_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          at: .

  run-rubocop:
    steps:
      - run:
          name: Run RuboCop
          command: |
            bundle exec rubocop

  run-tests:
    steps:
      - run:
          name: Run tests
          command: |
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out test_results/rspec/rspec.xml \
              --format progress \
              $TEST_FILES

  collect-reports:
    steps:
      # ref:https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results
      - store_test_results:
          path: test_results
      - store_artifacts:
          # テスト結果をtest-resultsディレクトリに吐き出す
          path: test_results
          destination: test-results
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results

  create-document:
    steps:
      - run:
          name: Create document
          command: |
            bundle exec yard
      - store_artifacts:
          # ドキュメントの結果をyard-resultsディレクトリに吐き出す
          path: ./doc
          destination: yard-results

  deploy-rubygems:
    steps:
      # ref:https://support.circleci.com/hc/ja/articles/115015628247-%E6%8E%A5%E7%B6%9A%E3%82%92%E7%B6%9A%E8%A1%8C%E3%81%97%E3%81%BE%E3%81%99%E3%81%8B-%E3%81%AF%E3%81%84-%E3%81%84%E3%81%84%E3%81%88-
      # read/write両方の権限が必要
      - add_ssh_keys:
          fingerprints:
            - "38:d2:72:5e:9f:67:93:9a:ec:95:94:a2:0e:bf:41:9e"

      # ref:https://circleci.com/docs/2.0/gh-bb-integration/#establishing-the-authenticity-of-an-ssh-host
      - run:
          name: Avoid hosts unknown for github
          command: |
            mkdir -p ~/.ssh
            echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
                  bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
                  ' >> ~/.ssh/known_hosts

      - run:
          name: Deploy RubyGems
          command: |
            curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials
            chmod 0600 ~/.gem/credentials
            git config user.name dodonki1223
            git config user.email $RUBYGEMS_EMAIL
            bundle exec rake build
            bundle exec rake release

  deploy-notification:
    steps:
      - slack/status:
          success_message: ':circleci-pass: RubyGemsにデプロイが完了しました\n:github_octocat: User: $CIRCLE_USERNAME'
          failure_message: ':circleci-fail: RubyGemsにデプロイが失敗しました\n:github_octocat: User: $CIRCLE_USERNAME'

jobs:
  setup:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - install-gem
      - save-gem-cache
      - save-workspace

  lint:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-rubocop

  test:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-tests
      - collect-reports

  document:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - create-document

  deploy:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - deploy-rubygems
      - deploy-notification

workflows:
  version: 2.1
  main:
    jobs:
      - setup
      - test:
          requires:
            - setup
      - document:
          requires:
            - setup
      - slack/approval-notification:
          message: ':circleci-pass: RubyGemsへのデプロイ準備が整っています\n:github_octocat: User: $CIRCLE_USERNAME\nデプロイを実行する場合は *Approve* を押してください'
          requires:
            - lint
            - test
          filters:
            branches:
              only: master
      - approval-job:
          type: approval
          requires:
            - slack/approval-notification
      - deploy:
          requires:
            - approval-job
          filters:
            branches:
              only: master
  # 定期でテストを実行する
  # ref:https://circleci.com/docs/ja/2.0/triggers/
  nightly:
    triggers:
      - schedule:
          cron: "0 22 * * *" # UTCで記述
          filters:
            branches:
              only:
                - master
    jobs:
      - setup
      - test:
          requires:
            - setup


更新内容

次世代の image を使用して executors を作成するように修正。

cimg に変更

  • cimg/ruby:2.6.6 を使用するように修正
version: 2.1
orbs:
  slack: circleci/slack@3.4.2
executors:
  base:
    docker:
      - image: cimg/ruby:2.6.6
        auth:
          username: dodonki1223
          password: $DOCKERHUB_PASSWORD
        environment:
          # Bundlerのパス設定が書き換えられ`vendor/bundle`ではなくて`/usr/local/bundle`を参照してしまい`bundle exec`でエラーになる
          # Bundlerのconfigファイル(pathの設定がされたもの)をworkspaceで永続化し`vendor/bundle`を参照するようにするための設定
          BUNDLE_APP_CONFIG: .bundle
          # ref: https://circleci.com/docs/2.0/faq/#how-can-i-set-the-timezone-in-docker-images
          TZ: "Asia/Tokyo"
    working_directory: ~/dodonki1223/qiita_trend

2020年11月:Ruby の orb を導入

Ruby の orb を使用することで自前で実装していた処理を orb で提供された command 使用することができるようになり記述の簡略化ができるようになった。

config.yml

Ruby の orb に寄せた config.yml です。

08_change_ruby_orb


config.yml
version: 2.1
orbs:
  ruby: circleci/ruby@1.1.2
  slack: circleci/slack@3.4.2
executors:
  base:
    docker:
      - image: cimg/ruby:2.6.6
        auth:
          username: dodonki1223
          password: $DOCKERHUB_PASSWORD
        environment:
          # Bundlerのパス設定が書き換えられ`vendor/bundle`ではなくて`/usr/local/bundle`を参照してしまい`bundle exec`でエラーになる
          # Bundlerのconfigファイル(pathの設定がされたもの)をworkspaceで永続化し`vendor/bundle`を参照するようにするための設定
          BUNDLE_APP_CONFIG: .bundle
          # ref: https://circleci.com/docs/2.0/faq/#how-can-i-set-the-timezone-in-docker-images
          TZ: "Asia/Tokyo"
    working_directory: ~/dodonki1223/qiita_trend

commands:
  save-workspace:
    steps:
      - persist_to_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          root: .
          paths: .

  using-workspace:
    steps:
      - attach_workspace:
          # working_directory からの相対パスか絶対パスを指定します
          at: .

  collect-reports:
    steps:
      - store_artifacts:
          # カバレッジの結果をcoverage-resultsディレクトリに吐き出す
          path: coverage
          destination: coverage-results

  create-document:
    steps:
      - run:
          name: Create document
          command: |
            bundle exec yard
      - store_artifacts:
          # ドキュメントの結果をyard-resultsディレクトリに吐き出す
          path: ./doc
          destination: yard-results

  deploy-rubygems:
    steps:
      # https://discuss.circleci.com/t/the-authenticity-of-github-host-cant-be-stablished/33133 と同じ現象で job が進まなくなるので以下の記事を参考に実装
      # ref:https://circleci.com/docs/ja/2.0/gh-bb-integration/#ssh-%E3%83%9B%E3%82%B9%E3%83%88%E3%81%AE%E4%BF%A1%E9%A0%BC%E6%80%A7%E3%81%AE%E7%A2%BA%E7%AB%8B

      - run:
          name: Avoid hosts unknown for github
          command: |
            mkdir -p ~/.ssh
            echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
                  ' >> ~/.ssh/known_hosts

      - run:
          name: Deploy RubyGems
          command: |
            curl -u dodonki1223:$RUBYGEMS_PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials
            chmod 0600 ~/.gem/credentials
            git config user.name dodonki1223
            git config user.email $RUBYGEMS_EMAIL
            bundle exec rake build
            bundle exec rake release

  deploy-notification:
    steps:
      - slack/status:
          success_message: ':circleci-pass: RubyGemsにデプロイが完了しました\n:github_octocat: User: $CIRCLE_USERNAME'
          failure_message: ':circleci-fail: RubyGemsにデプロイが失敗しました\n:github_octocat: User: $CIRCLE_USERNAME'

jobs:
  setup:
    executor: base
    steps:
      - checkout
      - ruby/install-deps
      - save-workspace

  lint:
    executor: base
    steps:
      - using-workspace
      - ruby/install-deps
      - ruby/rubocop-check

  test:
    executor: base
    steps:
      - using-workspace
      - ruby/install-deps
      - ruby/rspec-test:
          out-path: 'test_results/rspec/'
      - collect-reports

  document:
    executor: base
    steps:
      - using-workspace
      - ruby/install-deps
      - create-document

  deploy:
    executor: base
    steps:
      - using-workspace
      - ruby/install-deps
      - deploy-rubygems
      - deploy-notification

workflows:
  version: 2.1
  main:
    jobs:
      - setup
      - lint:
          requires:
            - setup
      - test:
          requires:
            - setup
      - document:
          requires:
            - setup
      - slack/approval-notification:
          message: ':circleci-pass: RubyGemsへのデプロイ準備が整っています\n:github_octocat: User: $CIRCLE_USERNAME\nデプロイを実行する場合は *Approve* を押してください'
          requires:
            - lint
            - test
          filters:
            branches:
              only: master
      - approval-job:
          type: approval
          requires:
            - slack/approval-notification
      - deploy:
          requires:
            - approval-job
          filters:
            branches:
              only: master
  # 定期でテストを実行する
  # ref:https://circleci.com/docs/ja/2.0/triggers/
  nightly:
    triggers:
      - schedule:
          cron: "0 22 * * *" # UTCで記述
          filters:
            branches:
              only:
                - master
    jobs:
      - setup
      - test:
          requires:
            - setup


更新内容

Ruby の orb の導入

  • circleci/ruby@1.1.2 を使用するように変更
version: 2.1
orbs:
  ruby: circleci/ruby@1.1.2

orbs で定義されている command と同等の処理を削除

  • Bundler のインストール、 gem のインストールの処理を削除
  • 以下の処理は Ruby の orb で定義されているのですべて削除し代替の処理に変更する
  install-bundler:
    steps:
      - run:
          name: Install bundler(2.1.0)
          command: gem install bundler:2.1.0

  # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
  restore-gem-cache:
    steps:
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

  install-gem:
    steps:
      - run:
          name: Install gem
          command: |
            # jobs=4は並列処理をして高速化するための設定(4つのjobで実行するって意味)
            bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3

  save-gem-cache:
    steps:
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

削除した処理を Ruby の orb の command に変更する

  • orb に変更する前と変更後の記述

修正前

jobs:
  setup:
    executor: base
    steps:
      - checkout
      - install-bundler
      - restore-gem-cache
      - install-gem
      - save-gem-cache
      - save-workspace

  lint:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-rubocop

  test:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - run-tests
      - collect-reports

  document:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - create-document

  deploy:
    executor: base
    steps:
      - using-workspace
      - install-bundler
      - deploy-rubygems
      - deploy-notification

修正後

jobs:
  setup:
    executor: base
    steps:
      - checkout
      - ruby/install-deps
      - save-workspace

  lint:
    executor: base
    steps:
      - using-workspace
      - ruby/install-deps
      - run-rubocop

  test:
    executor: base
    steps:
      - using-workspace
      - ruby/install-deps
      - run-tests
      - collect-reports

  document:
    executor: base
    steps:
      - using-workspace
      - ruby/install-deps
      - create-document

  deploy:
    executor: base
    steps:
      - using-workspace
      - ruby/install-deps
      - deploy-rubygems
      - deploy-notification

最後に

CircleCI で CI/CD を設定して運用してきたが自分の学びが多く、実装してすごく良かったと思う。
個人で CircleCI を運用することはすごく勉強になるので個人的にはすごくオススメします。
これからもこの設定ファイルを運用していき、気になった機能が増えたらすぐに実装していきたいと思います!

13
2
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
13
2