WerckerのRubyのboxでGruntを動かす設定

Jekyllのデプロイで利用しているWerckerにおいて、build時にGruntも実行しようとしたら想像以上にはまったのでメモしてみました。これ他にも嵌っている人いないのかなぁ。

なぜGruntを利用するか

本番にデプロイするときはCSSをminifyしたかった、という些細な理由です。jekyllで完結できればいいんですがね(ひょっとしたら何かいいパッケージあるのかしらん…ま、いいけど)。

結論

結論からいうと以下のymlで上手くいきました。

wercker.yml

box: wercker/ruby
# Build definition
build:
  steps:

    # 今回追記した部分 1
    - script:
        name: set nodejs emvironment
        code: |
          sudo apt-get update
          sudo apt-get install software-properties-common
          sudo add-apt-repository -y ppa:chris-lea/node.js
          sudo apt-get update
          sudo apt-get install nodejs
          sudo npm install -g grunt-cli
          sudo npm config set registry http://registry.npmjs.org/
          # sudo npm update
          # sudo npm cache clean
          sudo npm install
    # 追記部分ここまで

    # Run a smart version of bundle install
    # which improves build execution time of
    # future builds
    - bundle-install

    # 今回追記した部分 2
    - script:
        name: assests build
        code: |
          grunt build # ここでcssをminifyしている
    # 追記部分ここまで


    # A custom script step
    # that actually builds the jekyll site
    - script:
        name: generate site
        code: bundle exec jekyll build --trace
deploy:
  ~省略~

package.json

{
  "name": "none",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-shell-spawn": "~0.2.4",
    "grunt-contrib-watch": "~0.4.4",
    "grunt-contrib-cssmin": "~0.10.0",
    "grunt-contrib-compass": "*",
    "grunt-contrib-concat" : "*"
  }
}

この設定に至るまで…

最初は「まぁ、node突っ込んでnpm installすれば余裕っしょ?」と思って以下のように書いてました。

wercker.yml

    - script:
        name: set nodejs emvironment
        code: |
          sudo apt-get install nodejs
          sudo npm install

ところが、残念ながらbuildしてみたらエラー。

npm ERR! Error: failed to fetch from registry: grunt
npm ERR!     at /usr/share/npm/lib/utils/npm-registry-client/get.js:139:12
npm ERR!     at cb (/usr/share/npm/lib/utils/npm-registry-client/request.js:31:9)
npm ERR!     at Request._callback (/usr/share/npm/lib/utils/npm-registry-client/request.js:136:18)
npm ERR!     at Request.callback (/usr/lib/nodejs/request/main.js:119:22)
npm ERR!     at Request.<anonymous> (/usr/lib/nodejs/request/main.js:212:58)
npm ERR!     at Request.emit (events.js:88:20)
npm ERR!     at ClientRequest.<anonymous> (/usr/lib/nodejs/request/main.js:412:12)
npm ERR!     at ClientRequest.emit (events.js:67:17)
npm ERR!     at HTTPParser.onIncoming (http.js:1261:11)
npm ERR!     at HTTPParser.onHeadersComplete (http.js:102:31)
npm ERR! You may report this log at:
npm ERR!     <http://bugs.debian.org/npm>
npm ERR! or use
npm ERR!     reportbug --attach /pipeline/build/npm-debug.log npm
npm ERR! 
npm ERR! System Linux 3.2.0-54-virtual
npm ERR! command "node" "/usr/bin/npm" "install"
npm ERR! cwd /pipeline/build
npm ERR! node -v v0.6.12
npm ERR! npm -v 1.1.4
npm ERR! message failed to fetch from registry: grunt
npm ERR! 
npm ERR! Additional logging details can be found in:
npm ERR!     /pipeline/build/npm-debug.log
npm not ok

何やら「registryからとってこれませんでした」と。じゃあ、registry明記して差し上げましょう。

wercker.yml

    - script:
        name: set nodejs emvironment
        code: |
          sudo apt-get install nodejs
          # ↓今回追記
          sudo npm config set registry http://registry.npmjs.org/
          sudo npm install

これで行けるだろうと思ったら、またエラー。

npm ERR! Error: No compatible version found: grunt@'>=0.4.1- <0.5.0-'
npm ERR! Valid install targets:
npm ERR! ["0.1.0","0.1.1","0.1.2","0.2.0","0.2.1","0.2.2","0.2.3","0.2.4","0.2.5","0.2.6","0.2.7","0.2.8","0.2.9","0.2.10","0.2.11","0.2.12","0.2.13","0.2.14","0.2.15","0.3.0","0.3.1","0.3.2","0.3.3","0.3.4","0.3.5","0.3.6","0.3.7","0.3.8","0.3.9","0.3.10","0.3.11","0.3.12","0.3.13","0.3.14","0.3.15","0.3.16","0.3.17","0.3.13-a"]

今度は「package.jsonで指定されているGruntに適するバージョンないよ」って言われています。最大でも0.3.13-aまでしかない模様。いやいや、そんな馬鹿な。

npmのリストが古いのかと思ってnpm updateを設定。

wercker.yml

    - script:
        name: set nodejs emvironment
        code: |
          sudo apt-get install nodejs
          sudo npm config set registry http://registry.npmjs.org/
          sudo npm update
          sudo npm install

今度はcompassがだめそう…。試行錯誤してみましたが、同じようなエラーばかり出てきます。

npm ERR! Error: No compatible version found: grunt-contrib-compass
npm ERR! Error: No compatible version found: grunt-contrib-concat@'>=0.4.0- <0.5.0-'

なんか変だ、と思いnode.jsのバージョンを確認します。

wercker.yml

    - script:
        name: set nodejs emvironment
        code: |
          sudo apt-get install nodejs
          node --version # ←nodeのバージョンを確認するために追記
          sudo npm config set registry http://registry.npmjs.org/
          sudo npm update
          sudo npm install

これでbuildしたところ…。

$ node --version
v0.6.12

衝撃的なことに、nodeのバージョンが古い…。かなり古い。調べたところUbuntuにおいてapt-get nodejsでは最新版がインストールされない模様。 そこでnodeの最新版が登録されているregistoryを登録しようと思い以下のようにwercker.ymlに追記します。

wercker.yml

    - script:
        name: set nodejs emvironment
        code: |

          # nodejsの最新版を入れるための設定
          sudo apt-get install software-properties-common
          sudo add-apt-repository -y ppa:chris-lea/node.js
          # nodejsの最新版を入れるための設定ここまで

          sudo apt-get install nodejs
          node --version
          sudo npm config set registry http://registry.npmjs.org/
          sudo npm update
          sudo npm install

まずはレジストリを追加するコマンドadd-apt-repositoryを利用可能にするsoftware-properties-commonをインストール。 でもってadd-apt-repositoryを利用して、nodejsの最新版が利用できるrepositoryを追加します。

これでようやく上手くいきました。

結論としては以下の形になります。
(冒頭の記述を再掲)

wercker.yml

box: wercker/ruby
# Build definition
build:
  steps:

    # 今回追記した部分 1
    - script:
        name: set nodejs emvironment
        code: |
          sudo apt-get update
          sudo apt-get install software-properties-common
          sudo add-apt-repository -y ppa:chris-lea/node.js
          sudo apt-get update
          sudo apt-get install nodejs
          sudo npm install -g grunt-cli
          sudo npm config set registry http://registry.npmjs.org/
          # sudo npm update
          # sudo npm cache clean
          sudo npm install
    # 追記部分ここまで

    # Run a smart version of bundle install
    # which improves build execution time of
    # future builds
    - bundle-install

    # 今回追記した部分 2
    - script:
        name: assests build
        code: |
          grunt build # ここでcssをminifyしている
    # 追記部分ここまで


    # A custom script step
    # that actually builds the jekyll site
    - script:
        name: generate site
        code: bundle exec jekyll build --trace
deploy:
  ~省略~

なおsoftware-properties-commonapt-getで進めましたが、aptitudeでもいけました。

package.json

{
  "name": "none",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-shell-spawn": "~0.2.4",
    "grunt-contrib-watch": "~0.4.4",
    "grunt-contrib-cssmin": "~0.10.0",
    "grunt-contrib-compass": "*",
    "grunt-contrib-concat" : "*"
  }
}

boxを自分で作って利用するのもあり

今回のように面倒なことになるのであれば、最初から自前のboxを使った方が手っ取り早いと思いました。プリセットのwercker/rubyだとどうしても限界がありますね。