Technote

by sizuhiko

CakePHP2プラグインをTravisCIでビルドしているときに気をつけること

先日 @tenkoma さんが、FabricatePR をくれました。 しかももう枯れてる CakePHP2版 に。ありがたやー、と思っていましたら…

CIのビルドが失敗しています。

おや?直前までは通過していて、READMEのtypoが修正されただけなんですが…

(ただ直前は1年も前なのだが…)

ためしにRebuildしてみる

そういう小手先の問題ではないようだ….

TravisCIに書いてあるスクリプトの手順をローカルで実行してみる

うまく動く…

ビルド失敗の問題とは

失敗ビルドの一例でわかるとおり、PHPUnitのバージョンが期待値ではありません。

CakaPHP2ではPHPUnit3.7系しか使えません。 CakeTestSuiteDispatcherでPHPUnitのロードを試みていて、もしロードできないとTestShellでエラーになります。

CakePHP2のプラグインのテストを簡単に実行できるようにするためFriendsOfCake/travisを使っています。 このTravis用ツールは、PHPUnit3.7をインストールして、 Vendor の下にリンクしてくれるので、うまくPHPUnitは見つかるはずなのですが。

想定される原因としては、以下のような感じです。

  • PHPUnitが見つからない
  • 新しいPHPUnitが見つかった

CakePHPの日本語Slackで相談してみる

https://cakesf.slack.com/archives/C1FT02VQA/p1539927224000100

CakePHP2系のプラグインをTravis CIでテストするのに https://github.com/FriendsOfCake/travis を使っているのですが、PHPUnitへの参照がうまくできなくなっていて、解決した人っていたりしますか? 個人的に修正できそうなんて、試してみようかと思ったのですが、すでに対応済みの人がいたらなーと思い、聞いてみたいです

他のCakePHP2プラグインはビルド通っているのか?

  • https://github.com/lampager/lampager-cakephp2 は5ヶ月ぐらい前に通過している。でもPHPUnitのバージョンが新しい
  • https://github.com/cakephp/debug_kit/tree/2.2 はPHPUnit3.7使っているけど、 FriendsOfCake/travis を使ってない。ビルドは最近通過している
  • https://github.com/tsmsogn/Pas/ は FriendsOfCake/travis を使っていて、Slackで相談したらビルドまでしていただけた。ありがたや。通過している。

とにかくいろいろ試す

試すのに、別のブランチを切れば良かったのですが、まぁ簡単になおるだろうと Fabricate/cakephp2 ブランチで作業したのは、ちょっと後悔しています….

  • FriendsOfCake/travisのbefore_script.sh を呼び出す方法が、 travis_wait 付きに変わっていたので追従した。ビルドが不安定なことがあったが安定した
  • × FriendsOfCake/travis をローカルに fork して、ログを仕込んだりしてビルドを試みた(何も意味はなかった)
  • × FriendsOfCake/travisのbefore_script.shcomposer global install しているPHPUnitを削除して composer require で入れてみた(変化なし)
  • × include_path の先頭にPHPUnitへのパスを設定してみた(変化なし)
  • △ Slackで CAKE_REF 使うと良いかも?というアドバイスをいただいたので、入れてみた。PHPUnitへの参照としては変化がなかったけど、有用そうなのでそのまま採用した。
  • × 既存で composer.json があるのが、FriendsOfCake/travisを使っている他のプラグインと違ったので、 .travis.ymlbefore_script で消してみた(変化なし)

で、TravisCIの画面(のビルド結果コンソールではない部分)を見比べていたら、テストが通過している画面にはワーニングが表示されていて、自分のビルドには出ていないことが判明。 さらに過去に通過していたビルドにもワーニングが表示されていることを確認した。

何のワーニング?

This job ran on our Precise environment, which is in the process of being decommissioned. Please read about the status of the rollout on the blog, and take note that you can explicitly stay on Precise by specifying dist: precise in your .travis.yml.

意訳すると「このビルドは、Precise環境で実行されたけど、廃止予定です。もし続けて使いたければ .travis.yml に dist:precise と書いておけばOK。続きはBlogで」みたいなことです。 the blogも見ておいてください。

precise 指定でビルドしてみる

.travis.ymldist:precise を追加してみると….

ビルドが通過しました!!

ついでに古い composer.lock と composer.json も更新/削除しておきました。

詳しく調べた

現在のTravisでビルドするLinuxイメージは trusty なのですが、そこでPHP5.4などを利用しようとすると以下のようなメッセージがビルドコンソール中に表示されます。

5.4 is not pre-installed; installing Downloading archive: https://s3.amazonaws.com/travis-php-archives/binaries/ubuntu/14.04/x8664/php-5.4.tar.bz2 9.31s$ curl -s -o archive.tar.bz2 $archiveurl && tar xjf archive.tar.bz2 –directory /

ということで、PHPのイメージファイルをダウンロード&解凍してみました。 すると、PHPUnitが同梱されています。 そのバージョンは PHPUnit 4.8.35 でした。 そこかー、それ参照しちゃいましたか…

まとめ

CakePHP2プラグインを作ったことがあって、最近ビルドしていない方は漏れなく同様の事象になると思います。 これはFriendsOfCake/travis使っている、使っていないに関係なくです。

あなたの .travis.ymldist:precise が設定されていなければ、今のうちに追加しておきましょう。

ではステキなCakePHPライフを!

Google Cloud Builder を使って PHP7.2 のアプリケーションを GAE に継続的デプロイする

この記事は、PHPカンファレンス関西2018に参加してGAEに継続的デプロイする方法について発表してきましたの中で紹介しているGoogle Cloud Builderを利用してGAEのPHP SEへ自動デプロイするサンプルコードを最新に更新した解説記事です。

何が変わったのか?

PHPカンファレンス関西2018時点では以下のようになっていました。

  • GAEのPHPは5.5
  • Google Cloud Container Builder を利用

今日では以下のようになっています。

  • GAEのPHPで7.2が利用可能に
  • Cloud Container Builder は Cloud Build という名前に変更

gcloud コマンド利用上での変更

Dockerのバージョンがあがったことで gcloud コマンドから docker コマンドを実行するときに認証設定が必要になりました。 READMEにも反映していますが、以下のコマンドを実行しておく必要があります。

$ gcloud auth configure-docker

gcloud コマンドをアップデートしてみましたが、「PUSH TO DEPLOY のトリガーをセットする」については、まだできませんでした。 projects.builds/create APIは実装されているようなので、CLIから実行できるようになるのを心待ちにしています。

composer イメージの更新

PHP7.2を利用できるようになったので、 composer/composer:php5 のDockerイメージを composer/composer:alpine に変更しました。 composer/composer でも良かったのですが、 alpine ベースの方が軽量だし、いいですよね。

app.yaml の更新

基本的にここがメインなのですが、以下のような変更点があります。

  • runtime を php72 に変更
  • handlersapplication_readable は常に true
  • skip_files でデプロイしないファイルの指定は .gcloudignore ファイルへ移行する
  • / アクセスされたときの script 指定は auto に(ただし index.phppublic/index.php の場合のみで、他はパスを指定)

こういった変更は、Compatibility issues between PHP 5.5 and PHP 7.2にまとめられています。 ※ skip_files については書いていないので、実際にマイグレーションして確認は必要です(これは5.5から7.2の変更というよりは gcloud コマンドのバージョンアップに伴うものだから書いていないのかもしれないです)。

デプロイしてみよう

あとは、用意したコマンドを順番に実行してデプロイ環境を整備してから、 git push するだけで、PHP7.2のアプリケーションがデプロイできます。 githubのリポジトリが Cloud Source Repositories にミラーされるところなどは変わっていませんでした。

さいごに

この内容は プレPHPカンファレンス北海道 で発表する予定だったのですが、地震の影響でイベントが中止となったため、このブログにまとめました。

どこかで機会があれば、GAEとPHP7.2について発表してみたいなと思います。

web-i2cエレメントをより使いやすくしました。

先日のMaker Faire Tokyo 2018 に CHIRIMENコミュニティで参加しましたweb-i2c-element はどうなの? に記述した改良ポイントを使ったchirimen-pianoをアップしました。

変更したポイント:

変更の概要は以下のとおりです。

  • no-web-i2c スロットを指定すると、非対応メッセージを表示できるようになった
  • WebI2cSensorElement を使って、センサー毎の共通実装をなくし、より簡単にセンサーのカスタムエレメントが実装できるようになった
  • Polymer使ってなくても、タグだけを使ってセンサーの値が取得できるようなサンプルに変更した

では、それぞれの変更を詳しく見ていきましょう。

非対応メッセージの表示

chirimen-pianoのリポジトリにあるindex.htmlファイルを見てましょう。

<web-i2c>
  <grove-touch slave-address="0x5a"></grove-touch>
  <grove-gesture slave-address="0x73"></grove-gesture>
  <div slot="no-web-i2c">
    このデバイスはCHIRIMENではありませんが、ピアノ演奏はお楽しみいただけます。
  </div>
</web-i2c>

web-i2c タグの内側に no-web-i2c というslot名のタグを記述することで、 もしCHIRIMEN以外のデバイス(例えばPCなど)から、このページを表示するとメッセージを表示することができるようになります。 試しに、PCからchirimen-pianoのデモページにアクセスしてみてください。

WebI2cSensorElementを利用したカスタムエレメントの記述

最初のバージョンでは、 PolymerElement を使っていたため共通的な実装が多くなっていたのですが、 いくつかのセンサー実装をしてみて共通化できそうな箇所もわかってきたので、I2C用の親クラスを作ることにしました。

WebI2cSensorElement を使ったセンサーのクラスとして、GROVEタッチとGROVEジェスチャーのカスタムエレメントを作りました。

例としてchirimen-pianoのリポジトリにあるgrove-touch.jsファイルを見てましょう。

class GroveTouch extends WebI2cSensorElement {
  async init() {
    this._autoRead = true;
    await this._i2cSlave.write8(0x2b,0x01);
    await this._i2cSlave.write8(0x2c,0x01);
    await this._i2cSlave.write8(0x2d,0x01);
    await this._i2cSlave.write8(0x2e,0x01);
    await this._i2cSlave.write8(0x2f,0x01);
    await this._i2cSlave.write8(0x30,0x01);
    await this._i2cSlave.write8(0x31,0xff);
    await this._i2cSlave.write8(0x32,0x02);
    for(var i=0;i<12*2;i+=2){
      // console.log(i);
      var address = 0x41+i;
      // console.log(address);
      await this._i2cSlave.write8(address,0x0f);
      await this._i2cSlave.write8(address+1,0x0a);
    }
    await this._i2cSlave.write8(0x5d,0x04);
    await this._i2cSlave.write8(0x5e,0x0c);
  }

  async read() {
    const value = await this._i2cSlave.read16(0x00);
    // console.log(value);
    var array = [];
    for(var cnt = 0; cnt < 12; cnt ++){
      array.push(((value & (1 << cnt)) != 0)?true:false);
    }
    if (!this.value || (JSON.stringify(array) != JSON.stringify(this.value))) {
      this._setValue(array);
    }
  }
}

window.customElements.define('grove-touch', GroveTouch);

まず WebI2cSensorElement を継承したクラスを定義します。 このクラスには2つのオーバライド可能なメソッドがあります。

  • init
  • read

どちらも async メソッドにすることで I2Cスレーブデバイスからの応答を待ち合わせる(await)ことができるようになっています。

WebI2cSensorElement は、 init 呼び出し時にメンバー変数として _i2cSlave が利用可能になっています。 これはWeb I2Cのスレーブオブジェクトで、どんなメソッドが使えるかはWeb I2C API Specification4.6 Reading the value4.8 Writing a value を参照ください。 サンプルコードの slaveDevice_i2cSlave と同じものになります。

init を実装する

init ではI2Cデバイスの初期化コードを記述します。 とくに戻り値は必要ありません。

もしセンサーが読み取り可能なら、 this._autoRead = true; のように設定してください。 これを設定すると、インターバル間隔(デフォルトは100ミリ秒)ごとに read メソッドを呼び出してくれます。

read を実装する

init で _autoReadtrue に設定した場合、インターバル間隔ごとに呼び出されます。 センサーの値を読み取って、値が変わった場合は this._setValue(value) を呼び出してください。 エレメントの value プロパティに値が保持されると同時に、 value-changed イベントが発行されます。

普通のHTMLからセンサーを取り扱う

ふたたびchirimen-pianoのリポジトリにあるindex.htmlファイルを見てましょう。

<script>
  document.querySelector('grove-touch').addEventListener('value-changed', e => {
    document.querySelector('chirimen-piano-app').touchChanged(e.detail.value);
  });
  document.querySelector('grove-gesture').addEventListener('value-changed', e => {
    document.querySelector('chirimen-piano-app').gestureChanged(e.detail.value);
  });
</script>

センサー値の変更を受け取るには、センサーエレメントに対して value-changed イベントのリスナーを設定します。 値はイベントオブジェクトの detail.value に入っていて、センサーによってセットされる値(型も含め)が違います。

たとえば grouve-touch エレメントは、タッチセンサーの数分のBoolean配列がセットされ、 grove-gesture エレメントは、発生したジェスチャー名がセットされます。

さいごに

このようにHTMLからセンサーの値をコントロールできたり、センサーのエレメントを簡単に実装できるようになりました。 今後は、それぞれのエレメントやベースクラスを npm install で取得できるようにしたいと思っています。

また、以前作った WebGpioElementPolymer3 で書き換えていきたいなと思っています。

WebComponents と CHIRIMEN の融合は、私がそれぞれのコミュニティに参加して得られたもののアウトプットです。 もしこれらの活動に興味がありましたら、Polymer Japan CHIRIMEN Open Hardware Polymer.co-edo などの活動に参加ください。

Polymer.co-edo meetup #17 を開催しました

今年8回目となる Polymer.co-edo ミートアップ を開催しました。

今回の議題は

Polymer3 を使って、カスタムエレメントを作ってみよう!

ということで、またまたcodelabsにある、Polymer1系のエレメント作成では定番の Build your first Polymer element ですが、 これをPolymer3用に移植しました!(ついでに日本語化もしたよ!)

codelabsのはじめかた

はじめての Polymer 3 エレメントの作り方を順番に読み進めるだけで大丈夫です。 イベント中でも特にはまりどころはありませんでした。 (スクショが微妙に違うという指摘を受けましたが、これはPolymer1のベースが間違っているという…)

Polymer1や2は触ったことがあるけど、3はまだ、という人にはオススメの教材になっていると思います。

GDG DevFest の codelab にも採用されました

GDG DevFest Tokyo 2018 CodelabsのWEBカテゴリにもリンクされました。 WEBは#20 Your First Progressive Web Appと、はじめての Polymer 3 エレメントの作り方でした。 WEB自体、トライしてくれる人は少なかったのですが、当日は何名かの方にPolymerを試してもらえて良かったです(Polymer Japanステッカーを差し上げました!)。

次回は

9月にも開催を予定していたのですが、日程が調整できず、10月に予定どおり開催できる見込みです。 Doorkeeperのコミュニティページに今年の予定も書いてあるので参考にしてください。

前回も書きましたが、そろそろ、edoエレメントの開発をしないとなー、なんて思っています…

Maker Faire Tokyo 2018 に CHIRIMENコミュニティで参加しました

MFTokyo(昨年まではMFTと省略していましたが、今年からこのように変更となりました)のデモ準備として、 先日 CHIRIMEN Raspi setupという記事を書きましたが、これはその結果報告です。

デモ準備

実際にソースを書いて、動かしてみると 開封したばかりのGroveタッチセンサーが4つのうち1つだけ反応しません 。 ハブ側の裏にあるハンダ部分を触って通電させるとタッチ状態になるので、静電側が異常だということを認識し、 処理不良だから書い直せば大丈夫…と思い、前日の金曜日に秋葉原へ向かいしました。

実は8/3は半透明なブギーボード BB-11 の発売日で、翌日にMFTokyoへ持って行くなら量販店で買うしかない!と思いアキヨドにも行くつもりだったのです。 参考:13.8インチで半透明、ブギーボード新モデルが8月3日発売

何を作ったか

chirimen-piano という、ピアノアプリを作りました。

このアプリの特徴は以下のとおりです。

  • Polymer3で作られていて、以下のCustomElementsの実装評価を兼ねていた
    • web-i2c タグ
    • grove-gesture タグ
    • grove-touch タグ
  • CHIRIMENでなくても動作するWebアプリである
  • 4鍵(タッチセンサーの4つが対応)しかないが、左右に手を振ることでジェスチャーセンサーが反応し、音階が移動する。CHIRIMENでない場合は左右ボタンで移動

ちなみに昨年は Echigo という B2G OS ベースのボードで web-gpio エレメントを検証するために polymerchirimen というサンプルを作っていました。 これは人感センサーに反応すると、LEDが点灯するというものでした。

先日購入したものに追加して、以下の部品が必要になります。

完成画像は以下のとおりです。

苦労したこと

CHIRIMENでなくても動作するWebアプリ を目指して作り始めたら、Raspberry Pi版のpolyfillにいくつか問題があることがわかって、それを修正しながら進めたのでギリギリまで時間がかかりました。 こちら、まだchirimen-pianoにしか入っていませんが、近いうちに公式版へPRを送る予定です。

あとはセンサーの初期不良は、まぁあるものと思っていた方が良いですね。 最近あんまりハズレを引かなかったので忘れていました。

web-i2c-element はどうなの?

現時点はまだデモプログラム内での評価用ですが、今回思ったよりもうまく動作しそうなので、こちらもちゃんとエレメントとして分割したいです。 いくつか改善したいポイントがあります。

no-web-i2c 対応

まず CHIRIMEN 以外で動作させていたとき、 noscript タグみたいにして書けるようにする予定です。

現在は web-i2c.js にベタ打ちになっていますが

<div class="message">
  このデバイスはCHIRIMENではありませんが、ピアノ演奏はお楽しみいただけます。
</div>

これを利用側から指定できるようにしたいと思います。

<web-i2c>
  <div slot="no-web-i2c">
    このデバイスはCHIRIMENではありませんが、ピアノ演奏はお楽しみいただけます。
  </div>
</web-i2c>

WebI2cSensorElement 対応

センサーのタグは PolymerElement を継承して作るようにしていますが、これを WebI2cSensorElement のように親クラスを作って、センサータグ実装を楽にしたいと思っています。

現在のgrove-touchエレメントのソースコード を、以下のように書けるようにしたいと思っています。

class GroveTouch extends WebI2cSensorElement {
  async init(i2cSlave) {
    await i2cSlave.write8(0x2b,0x01);
    await i2cSlave.write8(0x2c,0x01);
    await i2cSlave.write8(0x2d,0x01);
    await i2cSlave.write8(0x2e,0x01);
    await i2cSlave.write8(0x2f,0x01);
    await i2cSlave.write8(0x30,0x01);
    await i2cSlave.write8(0x31,0xff);
    await i2cSlave.write8(0x32,0x02);
    for(var i=0;i<12*2;i+=2){
      var address = 0x41+i;
      await i2cSlave.write8(address,0x0f);
      await i2cSlave.write8(address+1,0x0a);
    }
    await i2cSlave.write8(0x5d,0x04);
    await i2cSlave.write8(0x5e,0x0c);
  }

  read(i2cSlave) {
    i2cSlave.read16(0x00).then((v)=>{
      var array = [];
      for(var cnt = 0;cnt < 12;cnt ++){
        array.push(((v & (1 << cnt)) != 0)?true:false);
      }
      if (!this.value || (JSON.stringify(array) != JSON.stringify(this.value))) {
        this.set('value', array);
      }
    })
  }

  defaultInterval() {
    return 1000;
  }
}
window.customElements.define('grove-touch', GroveTouch);

共通化のポイントは以下のような感じです。

  • 値のプロパティを value で共通化
  • エレメントのプロパティをWebI2cSensorElementで定義
  • ポートのオープンや、web-i2cエレメントとやりとりしてポートを設定するところなどをWebI2cSensorElementで定義
  • 値読み込みのインターバル制御をWebI2cSensorElementに移譲

2つのI2Cセンサータグを作ってみて、このぐらいは共通化しても大丈夫そうだし、便利そうだなと思っています。

on-change 対応

現時点はアプリもPolymerで書いているので、値の変更はデータバインディングでできているのですが、最終的にはタグから change イベントを飛ばすようにする予定です。

つまり利用者はPolymerを使わなくても、以下のようなHTMLコードを追加するだけで利用可能になることを想定しています。

<html lang="en">
  <head>
    <script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
    <script src="node_modules/@chirimen/polyfill/polyfill.js"></script>
    <script type="module" src="node_modules/@chirimen/web-i2c/web-i2c.js"></script>
    <script type="module" src="node_modules/@chirimen/grove-touch/grove-touch.js"></script>
    <script type="module" src="node_modules/@chirimen/grove-gesture/grove-gesture.js"></script>
  </head>
  <body>
    何かしらのアプリ


    <web-i2c>
      <div slot="no-web-i2c">
        このデバイスはCHIRIMENではありませんが、xxxxx。
      </div>
      <grove-touch slave-address="0x5a"></grove-touch>
      <grove-gesture slave-address="0x73"></grove-gesture>
    </web-i2c>

    <script>
      window.addEventListener('WebComponentsReady', e => {
        document.querySelector('grove-touch').addEventListener('change', e => {
          // 値が変わったときの処理
        });
      });
    </script>
  </body>
</html>

さいごに

WebComponentsを作るためのPolymerについては、 PolymerJapan コミュニティで活動しています。 毎月の集まりを Polymer.co-edoでも開催しているので、参加を待っています。

またCHIRIMENで、ブラウザからセンサーを動かしたいというような活動に興味があれば、コミュニティに参加ください。

どちらもユーザー主導で活動していますので、みなさまの参加をお待ちしております。