@Quramy です。
「アドカレやろうぜ」とか言い出した割には書くネタが全く思い付かないので、少し前に Wercker でドはまりした話を書きます。
Node.js でフロントエンドの開発をしていると、npm-scriptsにタスクを定義しておき、npm test
や npm run deploy
のように利用することは多いと思います。
"scripts": {
"test": "mocha",
"deploy": "webpack && gh-pages -d dist"
},
"devDependencies": {
"gh-pages": "^0.12.0",
"mocha": "^3.2.0",
"webpack": "2.2.0-rc.1",
...
},
npm run
では、./node_modules/.bin にPATHが通るので、ローカルにnpm iした mockaやwebpackのコマンドが使えるというアレです。
折角定義したタスクはCIでも利用したいのが人情です。Wercker の場合、次のようにyamlの script
部分に指定するだけです。
box: node:6.9
test:
steps:
- npm-install
- script:
name: test
code: npm test
deploy:
steps:
- script:
name: deploy
code: npm run deploy
ところが、上記yamlのように test
と deploy
というように複数のpipelineに分割していると、問題が発生します。
2つめ以降のpipelineでnpm-scriptsが正常に機能しないのです。
より正確には、npm-scriptsに記述している webpack
のようなコマンドが正しく動きません。ls -la node_modules/.bin
で確認してみると分かるのですが、node_modules/.bin配下のsymbolic linkが壊れてしまっているのです。
lrwxr-xr-x 1 root root 0 12 19 00:48 gh-pages
lrwxr-xr-x 1 root root 0 12 19 00:48 mocha
lrwxr-xr-x 1 root root 0 12 19 00:48 webpack
上記のような状態になります。各コマンドの実行権限は残っているので、音もなくreturn code 0で終了するという状態になります。
symlinkが正常な状態であれば /.bin配下から各パッケージのコマンドへlinkが参照できるはずです。
lrwxr-xr-x 1 root root 18 12 19 00:48 mocha -> ../mocha/bin/mocha
werckerでは、各pipelineの最後にstoreというstepが実行されます。store stepで、プロジェクトルート配下をまるごと一時的にコピーし、次のpipelineではコピーした内容を復旧してからユーザー定義のstepが開始されます。
Werckerは1つのpipelineにつき、1つのcontainer を起動するため、pipelineを分けると別containerでの実行となるため、このような機構があるのでしょう。そして (何故かは分かりませんが) werckerのstore/restoreの過程でsymlinksが破壊されてしまいます。
storeする際にsymlinkが破壊されるのであれば、それは復旧すれば良いじゃない、ということで werckerのstepを作ってみました。 wacul/store-link 。
box: node:6.9
test:
steps:
- npm-install
- script:
name: test
code: npm test
- wacul/store-link:
type: store
prefix: node_modules/.bin
deploy:
steps:
- wacul/store-link:
type: restore
prefix: node_modules/.bin
- script:
name: deploy
code: npm run deploy
指定したディレクトリのsymlink情報を引っこ抜いて保持しておき、restoreに再度 ln -s
するstepです。上記のように、pipelineの最後にlinkをstoreし、他のpipelineの先頭でrestoreして使います。
よくよく考えたら、 node_modules/.bin
であれば、npm rebuild
を叩けば復旧できるんじゃないか、という事に気づいたのは、このstepを作ってしまってからです。
こいつの場合 node_modules
に限らず、simlink全般に対して汎用的に使えるので、全くの無意味だったわけではないですが。
もし似たような問題で悩んでいる人がいたら、お試しください。それでは、また。