まちいろエンジニアブログ

南池袋のWebサービス開発会社、株式会社まちいろのエンジニアブログです。

Ruby/Padrino/MySQL 5.7 プロジェクトをCircleCI 2.0 に移行してみた

こんにちは、まちいろの工藤です。

まちいろでは CI に CircleCI を利用していますが、先日ついに CircleCI の 2.0 が正式リリースされましたね。 まだ 2.0 に対応していなかったので、既存のプロジェクトを 2.0 に対応させてみました。

circleci.com

対象プロジェクトの技術スタック

対象プロジェクトは Ruby/Padrino で書かれた至って普通の Web アプリケーションって感じです。

移行手順

CircleCI 2.0 への移行は、2.0 用の設定ファイルを push するだけです。

2.0 から、設定ファイルが circle.yml から .circleci/config.yml に変更されています。 Circle CI のサイトから既存のリポジトリを選択すると config.yml の雛形が出てくるので、そちらを参考にすると良いかと思います。

以下、最終的にできあがった config.yml です。

version: 2

jobs:
  build:
    working_directory: ~/repo
    docker:
      - image: circleci/ruby:2.4.1-node-browsers
        environment:
          DB_HOST: 127.0.0.1
      - image: mysql:5.7
        command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --innodb-large-prefix=true --innodb-file-format=Barracuda
        environment:
          MYSQL_USER: foo
          MYSQL_PASSWORD: foo
          MYSQL_DATABASE: foo
          MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
          MYSQL_ROOT_HOST: '%'
    steps:
      - checkout

      - run:
          name: install dockerize
          command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && tar -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
          environment:
            DOCKERIZE_VERSION: v0.5.0

      - run:
          name: Wait for db
          command: ./dockerize -wait tcp://localhost:3306 -timeout 1m

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

      - run:
          name: bundle install
          command: bundle install --jobs=4 --path vendor/bundle

      - save_cache:
          key: foo-vendor-bundle-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

      # Database setup
      - run:
          name: init db
          command: RACK_ENV=test DB_YAML=tools/circleci/database.yml bundle exec rake db:initdb

      # run tests!
      - run:
          name: rspec
          command: RACK_ENV=test DB_YAML=tools/circleci/database.yml bundle exec rake spec

移行時のポイント

  • MySQL コンテナの環境変数 MYSQL_ROOT_HOST を指定して、テストを実行するコンテナから疎通可能とする
  • dockerize を利用して、MySQL が起動した後にテストが実行されるようにする
  • restore_cache/save_cache を利用して、bundle install の結果をキャッシュして高速化
  • Padrino の場合、DB 設定を config/database.rb に記述するため、DB_YAML に database.yml のパスを渡したらそちらの設定を適用するようコードを修正

移行した結果

CircleCI 2.0 に移行したら、テストの実行時間が半分以下まで減りました :)

コード解析・フォーマットツールを導入しよう

こんにちは、まちいろの工藤です。

まちいろでは言語毎にコード解析・フォーマットツールを導入しています。 弊社メンバーがよく使っているエディタ「Atom」のプラグインと合わせて、いくつか紹介したいと思います。

Ruby

Ruby には RuboCop という Ruby コード静的解析ツールがあります。 コーディングルールは .rubocop.yml に記述していきます。

github.com

RuboCop には、実行時にコーディング規約に準拠する形にコードを修正する autocorrect 機能があります。 例えば文字列は基本シングルクォーテーションで囲む、という規約だった場合、 ダブルクォーテーションで囲まれている部分を自動でシングルクォーテーションに修正します。

autocorrect を有効にするには、実行時に -a オプションを付与します。

$ rubocop -a

...

nn files inspected, nn offenses detected, nn offenses corrected

Atom から実行するには、linter-rubocop プラグインを導入します。 また、rubocop-auto-correct プラグインを導入すると、ファイル保存時に autocorrect を行うことができて便利です。 Golang の gofmt を使っている感覚でコーディングできます。

JavaScript

JavaScript でのコード解析は ESLint が有名です。 コーディングルールは .eslintrc に記述していきます。

eslint.org

ESLint にも autofix という自動修正のオプションがあります。 Atom では、linter-eslint プラグインを導入すると、コード解析だけでなくファイル保存時のフォーマットも行うことができます。

また、最近 (?) Prettier というコードフォーマッタが話題です。 既に Star の数が ESLint を超えてますね。。

github.com

こちらは Golang における gofmt 的な役割で、コードフォーマットに特化しています。 既に ESLint を導入している場合は、https://github.com/prettier/prettier-eslint を利用することで、.eslintrc の設定内容を元にフォーマットすることができます。

Atomprettier-atom プラグインを導入すると、ファイル保存時にフォーマットを実行することが可能です。

CSS

CSS では stylefmt (以前は cssfmt という名称だったようです) というコードフォーマッタがあります。 Stylelint との連携も可能なようですが、まちいろでは stylefmt のデフォルトルールで利用しています。

https://github.com/morishitter/stylefmt

Atomatom-stylefmt プラグインを導入すると、ファイル保存時にフォーマットを実行することが可能です。 ただし最新バージョンでは、language-postcss プラグインを導入しているとうまく動きませんでした。

最後に

いかがでしたでしょうか。

コードレビューを実施している現場は多いと思いますが、レビューの際にインデントや括弧の位置など、本質的ではないところを指摘するのは無駄なので、こういったツールを導入して自然にルールに準拠できるようにしていくと良いと思います。

jQueryのセレクタをまとめてみました

こんにちは、まちいろの井上です。
jQuery で何かしたいときに、これってどうやって書くんだったかなと調べたりすることってありませんか? よく使うものを度忘れしてしまったり、使用頻度が低いものであったり、知っているけどどのように使うんだろう、などあるかと思います。

そこで今回は備忘録もかねて、jQueryの代表的なセレクタについてまとめてみました。

基本セレクタ

 htmlの要素名を設定することで、指定した要素をすべて選択します。

 $('div')  // 全てのdivタグが対象


 #の後にid名を付けると、指定したid属性を持つ要素を選択します。

  $('#formId')  // id名が「formId」の要素が対象


 .の後にクラス名を付けると、指定したクラス名を持つ要素を選択します。

  $('.testClass')  // クラス名が「testClass」の要素が対象

階層指定

 要素の配下にある全ての子孫要素を選択します。

 $('form button') // formタグ配下にある全てのbuttonタグが対象


 親要素の直下にある全ての子要素を選択します。

 $('.testClass button') // testClassクラス直下にある全てのbuttonタグが対象


  • 隣接セレクタ $(‘直前の要素 + 隣接する要素’)

 直前の要素の直後にある隣接する要素を選択します。

 $('div + input') // divタグの直後にあるinputタグが対象

  この場合、divタグの直後にinputタグがない場合は選択されませんので注意してください。

属性フィルタ

  • $(‘[属性名]’)

  属性名をもつ要素を選択します。

  $('input[class]')// class属性を持つすべてのinputタグが対象


  • $(‘[属性名 = 値]’)

  属性名と一致する要素を選択します。

  $('input[class=test]') // class属性の値が「test」のinputタグが対象


  • $(‘[属性名 != 値]’)

    属性名と異なる要素を選択します。

  $('input[class!=test]') // class属性が「test」以外のinputタグが対象


  • $(‘[属性名 ^= 値]’)

  属性名で始まる要素を選択します。

  $('input[name^=sample_]') // name属性が「sample_」で始まるinputタグが対象


  • $(‘[属性名 $= 値]’)

  属性名で終わる要素を選択します。

   $('input[name$=_test]') // name属性が「_test」で終わるinputタグが対象


  • $(‘[属性名 *= 値]’)

  属性名を含む要素を選択します。

   $('input[name*=_t]') // name属性に「_t」が含まれるinputタグが対象

フォームフィルタ

  • $(‘:checked’)

  チェックボックスや、ラジオボタンで選択されている要素を選択します。

   $('[name="radio"]:checked')  // name属性が「radio」でチェックが選択されている要素が対象


  • $(‘:selected’)

    select要素で選択されている要素を選択します。

   $('select[name="selectTest"] > option:selected')  // name属性が「selectTest」のプルダウンで、選択されている要素が対象

可視性フィルタ

  • $(‘要素名:visible’)

  表示状態の要素を選択します。

   $('input:visible')  // 表示状態のinputタグが対象


  • $(‘要素名:hidden’)

  非表示状態の要素を選択します。

   $('div:hidden')  // 非表示状態のdivタグが対象

子要素フィルタ

  親要素内にある最初の子要素を選択します。
  指定したセレクタが最初の子要素でない場合は選択されません。

   $('h2:first-child')  // 親要素内にある最初の子要素がh2タグの場合に選択される


  親要素内にある最後の子要素を選択します。
  指定したセレクタが最後の子要素でない場合は選択されません。

   $('p:last-child')  // 親要素内にある最後の子要素がpタグの場合に選択される


  親要素内に1つだけ子要素を持つ場合に、指定された要素を選択します。

   $('p:only-child') // 親要素内に一つだけ子要素を持ち、その子要素がpタグの場合に選択される


  親要素内にあるセレクタで、引数に指定した要素を選択します。
  引数にはodd(奇数番目)、even(偶数番目)、数値n(数値の倍数番目の子要素)を指定することができます。

   $('p:nth-child(odd)')   // 親要素内で偶数番目の要素がpタグの場合に選択される
   $('p:nth-child(3)')     // 親要素内で3番目の要素がpタグの場合に選択される
   $('p:nth-child(3n)')    // 親要素内で3の倍数の要素がpタグの場合に選択される

最後に

今回は代表的なセレクタを紹介しましたが、他にも色々なセレクタがあります。
ここでは紹介できなかった他のセレクタについては、jQueryAPI ドキュメントのSelectorsを参照いただければと思います。