読者です 読者をやめる 読者になる 読者になる

MatchinGoodエンジニアブログ

MatchinGood株式会社のエンジニアリング事情を共有します

php7 + phpdbgで高速カバレッジ出力

f:id:kota-inamori:20170317193440j:plain

マッチングッド株式会社でアルバイトをしています稲森(id:kota-inamori)です。

先日は、今私が関わっているプロジェクトのphpのバージョンを挙げた際のTipsについて投稿しました。

blog.matchingood.com

今日は、php7にバージョンアップしたことによって可能になった、phpdbgによるコードカバレッジ出力について書きたいと思います。

phpdbgとは

phpdbg | php debugger

phpdbgは、phpのデバッガです。デバッガというとphpの場合似たようなものとしてxdebugもありますが、xdebugはあくまでphpの拡張モジュールであって、その恩恵を最大限に受けるにはIDEが必要不可欠です。

一方、phpdbgは端末上での逐次実行やブレークポイントの設定など、デバッガとしての実行を端末環境で行うことができます。C言語に馴染みがある人ならgdbライクだというとわかっていただけると思います。

phpdbgはphp5.6からphpのコアモジュールとして採用されており、phpがインストール済みなら既にインストールされています。

今回はphpdbgのデバッガとしての使用についてはひとまず置いておいて、このphpdbgを用いたカバレッジの出力についてご紹介したいと思います。

今までのコードカバレッジの出力

現在私が関わっているプロジェクトでは、CIでのテストの際にコードカバレッジを出力しています。PHPUnitを用いている場合は以下のようなコマンドです。

/path/to/phpunit --coverage-html=$CIRCLE_ARTIFACTS

これによって、$CIRCLE_ARTIFACTSの表すディレクトリにコードカバレッジがhtmlで出力されます。しかし、これがとても重い…

これまでのプロジェクト上のCI上のテスト(カバレッジ出力込)の実行時間について、過去の記録を調べてみました。CIはCircleCIを利用しています。

environment assertions time
php5.6 + phpunit 4.8.29 726 8m35s
php7.0 + phpunit 4.8.29 724 2m56s
php7.0 + phpunit 5.7.15 692 3m04s

php5.6時代は700程度のアサーションでも8分以上かかっています。それに対してphp7恐るべし…!php5.6に比べて約3倍の高速化です。phpunitのバージョンアップはLaravel5.4へのバージョンアップの際に行いましたが、これについてはあまり関係していなさそうです(むしろ遅くなってる?)

とはいえ、これらのテストはカバレッジを出力しなければ、どれも30秒程度で終わります。つまり、CIでのテストを高速化するならこのカバレッジ出力の部分を高速化したい!ということになります。これを叶えるのがphpdbgです。

phpdbgを用いたコードカバレッジ出力

従来のカバレッジ出力では、ドライバとしてxdebugを利用しています。このドライバをphpdbgに変更するには、先ほどのコマンドの先頭にphpdbg -qrrをつけるだけです。

phpdbg -qrr /path/to/phpunit --coverage-html=$CIRCLE_ARTIFACTS

phpdbgはphpのコアモジュールなので、phpにPATHが通っているならばphpdbgも通っていると思われるので、パスは省略しています。

phpdbgのコマンドオプションの説明についてはGoogle先生にお任せしますが、ここでの-qrrは、「起動時のタイトル・バージョン表示を省略し、引数に指定されたスクリプトを即時実行した後、phpdbgを終了する」という意味になります。

では、phpunitによるテスト+phpdbgによるカバレッジ出力の結果を、先ほどの結果と合わせて見てみましょう。

environment assertions time
php5.6 + phpunit 4.8.29 726 8m35s
php7.0 + phpunit 4.8.29 724 2m56s
php7.0 + phpunit 5.7.15 692 3m04s
php7.0 + phpunit 5.7.15 with phpdbg 682 37s

なんと軽々と1分を切っていきました。すさまじい速さです…

全体としても2分以上の短縮ができました。CIの高速化は熱心に取り組むにはややハードルの高いissueですが、この程度の変更で短縮できるならとても良いですね!

注意事項

phpdbgについては、php5.6からコアモジュールとして公式に配布されていますが、カバレッジの出力に関してはphp7からのサポートとなります。これについては、PHPUnitカバレッジ出力に利用しているPHP_CodeCoverageというコンポーネントの要件に依存しているためです。

最後に

コードカバレッジの出力をphpdbgを通して行うことで、CIの時間を2分以上早めることができました!導入も手軽なので、php7を用いたプロダクトでカバレッジ出力がしたいのならば是非おすすめしたい方法です!

弊社では、開発環境の効率化にも積極的に取り組める、熱意あるエンジニアを募集しています!

是非一緒に開発しませんか?

en-gage.net

AlpineLinux上のLaravelアプリケーションのphp5.6 -> 7.0の環境アップグレードでコケた話

f:id:kota-inamori:20170309201316j:plain

こんにちは。マッチングッドアルバイトの稲森(id:kota-inamori)です。

現在私が携わっているプロジェクトでは、DockerコンテナとしてAlpineLinuxを用いて、PHP5.6 + Laravel5.3でアプリケーションの開発・運用をしています。

先日、PHP5.6のアクティブアップデート期間が終了しました

これに伴って本アプリケーションもPHP7に移行してみようとしたのですが、すごく微妙な落とし穴にハマってしまったので、Tipsとして書き残したいと思います。

AlpineLinuxにおけるPHP

AlpineLinuxを用いたPHPアプリケーション環境の構築には、まずイメージの選択肢があります。自分がわかる範囲では以下の2つです。

前者の場合はベースイメージにalpine以外にも選択肢があります。こちらはDockerfile上で指定されたバージョンのPHPのソースをダウンロードしてビルドしています。

後者はプレーンなOSイメージですが、公式のレポジトリでビルド済みのPHPが配布されているのでこれを利用します。もちろん自前でビルドすることもできます。

私の携わっているプロジェクトは後者を用いていますが、さいことPHPに特化するのであれば、PHPが公式にメンテナンスしている前者が良いかと思います。

Alpine公式レポジトリのPHPについて

現在、AlpineLinuxの公式レポジトリでは、PHP5.6(php)とPHP7.0(php7)がそれぞれ別パッケージとして配布されています。以前はこのPHP5.6と、各種拡張機能(php-openssl, php-pdo_mysql, etc.)をレポジトリからインストールして運用していました。以下は従来のDockerfileの一部です。apkはalpineLinuxにおけるパッケージマネージャのコマンドで、ubuntuでいうapt-get、centOSでいうyumのようなものです。

FROM alpine:3.3

RUN apk --no-cache add apache2 php-apache2 \
        php php-fpm php-json php-zlib php-xml php-pdo php-phar \
        php-openssl php-curl php-pdo_mysql php-mysql php-mysqli \
        php-gd php-ctype \
    && mkdir -p /run/apache2/ \
    && rm -rf /var/www/localhost/htdocs/index.html \
    && ln -sf /dev/stdout /var/log/apache2/access.log \
    && ln -sf /dev/stderr /var/log/apache2/error.log

各種拡張モジュールはphp-*という形式で提供されています。どうやらPHP7も同じようにphp7-*という形式であるようなので、Dockerfileを以下のように修正してみる!

FROM alpine:3.5

RUN apk --no-cache add apache2 php7-apache2 \
        php7 php7-fpm php7-json php7-zlib php7-xml php7-pdo php7-phar \
        php7-openssl php7-curl php7-pdo_mysql php7-mysqli \
        php7-gd php7-ctype \
    && mkdir -p /run/apache2/ \
    && rm -rf /var/www/localhost/htdocs/index.html \
    && ln -sf /dev/stdout /var/log/apache2/access.log \
    && ln -sf /dev/stderr /var/log/apache2/error.log \
    && ln -sf /usr/bin/php7 /usr/bin/php

…HTTP Error Code 500。。。(・・?

ひっそりと隠れていたmbstring

docker logsを通してapacheに出力されたエラーを見てみると、Mbstringの関数が未定義だということを言われている。そういえばmbstringはPHPの拡張モジュールでした。 Laravelの必要要件にもmbstringがあります。これが足りないのか…?

[Tue Mar 07 11:31:27.898014 2017] [:error] [pid 7] [client 172.17.0.1:51690]
PHP Fatal error:  Uncaught Error: Call to undefined function Symfony\\Polyfill\\Mbstring\\iconv_strpos() 
in /var/www/localhost/htdocs/vendor/symfony/polyfill-mbstring/Mbstring.php:358\nStack 
trace:
\n#0 /var/www/localhost/htdocs/vendor/symfony/polyfill-mbstring/bootstrap.php(32): Symfony\\Polyfill\\Mbstring\\Mbstring::mb_strpos(NULL, '/json', 0, 'UTF-8')
\n#1 /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Support/Str.php(72): mb_strpos(NULL, '/json')
\n#2 /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Http/Concerns/InteractsWithContentTypes.php(34): Illuminate\\Support\\Str::contains(NULL, Array)
\n#3 /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Http/Request.php(312): Illuminate\\Http\\Request->isJson()
\n#4 /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Http/Request.php(340): Illuminate\\Http\\Request->getInputSource()
\n#5 /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Http/Request.php(59): Illuminate\\Http\\Request::createFromBase(Object(Illuminate\\Http\\R in /var/www/localhost/htdocs/vendor/symfony/polyfill-mbstring/Mbstring.php on line 358
172.17.0.1 - - [07/Mar/2017:11:31:27 +0000] "GET / HTTP/1.1" 500 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.90 Safari/537.36"
172.17.0.1 - - [07/Mar/2017:11:31:47 +0000] "-" 408 - "-" "-"

そこで、公式レポジトリを調べてみたところ、

  • PHP5.6(php)では、mbstringがメインパッケージにバンドルされていた

  • PHP7(php7)では、別パッケージとして配布されている

ことが判明。なるほど、動かないわけだ…

さらなる追い打ち、sessionモジュール

そこでphp7-mbstringを入れて再度イメージをビルドしてコンテナ作成、アクセスしてみると、今度は画面が真っ白に…やはり内部エラー(500)が返ってきていました。

もう一回エラーログを見ると、今度はSessionHandlerInterfaceがないと言われています。これはPHPの拡張モジュールで定義されているインターフェースのようですね。

PHP: SessionHandlerInterface - Manual

[Thu Mar 09 10:46:27.561882 2017] [:error] [pid 7] [client 172.17.0.1:49232] PHP Fatal error:  Interface 'SessionHandlerInterface' not found in /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Session/CookieSessionHandler.php on line 10
[Thu Mar 09 10:46:27.585695 2017] [:error] [pid 7] [client 172.17.0.1:49232] PHP Fatal error:  Uncaught TypeError: Argument 2 passed to Illuminate\\Session\\Store::__construct() must be an instance of SessionHandlerInterface, instance of Illuminate\\Session\\CookieSessionHandler given, called in /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Session/SessionManager.php on line 169 and defined in /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Session/Store.php:56\nStack 
trace:
\n#0 /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Session/SessionManager.php(169): Illuminate\\Session\\Store->__construct('laravel_session', Object(Illuminate\\Session\\CookieSessionHandler))
\n#1 /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Session/SessionManager.php(39): Illuminate\\Session\\SessionManager->buildSession(Object(Illuminate\\Session\\CookieSessionHandler))
\n#2 /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Support/Manager.php(87): Illuminate\\Session\\SessionManager->createCookieDriver()
\n#3 /var/www/localhost/htdocs/vendor/laravel/framew in /var/www/localhost/htdocs/vendor/laravel/framework/src/Illuminate/Session/Store.php on line 56
172.17.0.1 - - [09/Mar/2017:10:46:26 +0000] "GET / HTTP/1.1" 500 1 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.90 Safari/537.36"

このパッケージもやはりmbstringと同様、5.6まではメインパッケージで既に有効になっていたものが、別パッケージになっていたようです。

mbstringはまだしも、sessionはPHP使ってれば絶対使いそうな気がするので分けなくても良いような気がしますが…その辺りのメンテナの意図が気になるところです。

まとめ

上記を踏まえて、php7-mbstringとphp7-sessionパッケージを追加してビルドしたところ、ようやくうまくいきました。

500エラーはクライアントサイドの情報量が少ないので、サーバーサイドのログを探らなくてはいけないのでちょっと大変ですね。

FROM alpine:3.5

RUN apk --no-cache add apache2 php7-apache2 \
        php7 php7-fpm php7-json php7-zlib php7-xml php7-pdo php7-phar \
        .
        .
        .
        php7-mbstring php7-session \
    && mkdir -p /run/apache2/ \
    .
    .
    .

弊社では、開発時に発生する未知の問題にも積極的に取り組める、熱意のあるエンジニアを募集しています!

是非一緒に開発しませんか?

en-gage.net

Typescript & Immutable.jsで快適データ構造操作

f:id:kota-inamori:20170221193312j:plainこんにちは。マッチングッドのアルバイトエンジニアの稲森(id:kota-inamori)です。

今回は、業務で使っているTypescriptと、javascriptのデータ構造ライブラリであるImmutable.jsの合わせ技についてご紹介したいと思います。

Typescriptとは

MicroSoft社が開発を始め、今やGithubOSSとして開発が続けられているAltJS(JSにコンパイルできる言語)の一つです。

TypeScript - JavaScript that scales.

この言語の一番の特徴といえば、静的な型付けによるコンパイル時型チェックです。Typescriptにはnumber,string,booleanなどのプリミティブ型を始め、Java等で馴染みのあるInterfaceや、Classも存在します。また、ジェネリクスによる型のパラメータ化もできます。

もちろん、コンパイル後にはこれらの情報はほぼ落ちてしまうのですが、型チェックの恩恵が受けられるので、主にプログラミングの際の補完がかなり優秀です。今回はこの補完という要素についてfocusしてみたいと思います。

Immutable.jsとは

Immutable.js

こちらは、javascriptにおけるイミュータブルなデータ構造を提供してくれるライブラリです。プリミティブな実装にもあるArrayやMapの他にも、SetやListなんかもあります。 javascriptは組み込みのデータ構造操作メソッドがあまり充実しておらず、またimmutable/mutableの区別が曖昧なものが多いです。このライブラリは、その問題を解消し、元データに手を加えることなく様々な操作を可能とします。

Immutable.jsとjavascriptの相性

さて、このImmutable.jsですが、ドキュメントを見てみるとなにやらjavascriptらしくない(?)型要素が満載のドキュメントになっています。 C++Javaなどに慣れている人ならばピンと来るのですが、ここで使われているのはジェネリクスというものです。 たとえばMap<K, V>という型は、Key(連想配列の添字)がK型、値(連想配列の中身)がV型であるということを表しています。ここでKとVは型を表すパラメータとして使われています。 そんなもの動的型付けの前じゃ意味ないじゃないか!という意見はごもっともです。実際javascript上では、この型付けによる恩恵はほぼありません。 (とはいえ、リスト操作に関しては組み込みのものよりも多くのメソッドがあり、またImmutable性を保証してくれるので使うモチベーションは大いにあります。)

型付けによる恩恵

もちろんImmutable.jsの型定義ファイルは公開されており、Typescriptでこの型の恩恵を大いに受け取ることができます。コンパイル時チェックもさることながら、コーディング中の補完もかなり優秀です。

たとえば、Aくんが以下のようなプログラムを書いたとします。中身はとても適当なのですが、とりあえずリストに対して複雑な処理がしたいということだけ察してください。

// user.ts
interface User {
    id: number;
    name: string;
    friends: User[];
}

export default User;
// main.ts
import User from './user';
import * as Immutable from 'immutable';

let bob: User = {
    id: 1,
    name: "Bob",
    friends: []
};

let alice: User = {
    id: 2,
    name: "Alice",
    friends: [bob]
};

let john: User = {
    id: 3,
    name: "John",
    friends: [bob]
};

let eliza: User = {
    id: 4,
    name: "Eliza",
    friends: [alice]
};

let users: User[] = [bob, john, alice];

Immutable.Seq(users)
    .sortBy((user) => user.id)
    .map((user) => {
        user.friends.push(eliza);
        return user;
    })
    .filter((user) => user.name.length > 4)
    .reverse()
    .last();

上記main.tsにおける最後のメソッドチェーンの結果はUser型であることが期待されますが、書いた後のAくんにはほんとにUser型が返ってくるかどうかわかりません。型エラーがあれば最終的にコンパイル時にわかるのでよいのですが、書いたそばからコンパイルするのは面倒です。本当は書いてる最中にわかればいいのに…そんな時に補完機能とその型の表示機能が役に立ちます!(ここではVisualStudioCodeを使用しています)

f:id:kota-inamori:20170221185606g:plain

すぐさまUser型であることがわかりました!その他にも、補完するときにそのドキュメントも表示されていることがわかるとおもいます。もちろん型を明示するのはプログラマの責任ですが、コンパイル時だけでなくコーディング時にもその恩恵を受けることができます。

まとめ

今回はTypescriptとImmutable.jsの組み合わせについてご紹介しました。型付けによる補完機能の強化はTypescript自体の特徴の一つではありますが、データ構造の操作という中身がわかりづらい操作をする場合だと、その恩恵が顕著に得られることがわかります。

弊社では、最新の技術をできるだけ取り入れながら、よりよいプロダクトをともに作っていく仲間を募集しています!

是非一緒に開発しませんか?

en-gage.net

Alpine Linux 上でPHPのiconvがうまく動かない件の解決策

f:id:takuseno:20170214143923j:plain

エンジニアアルバイトの妹尾(id:takuseno)です。

このブログでは何度もDocker関連の記事をあげていますが、今回もDockerの記事です。

弊社では Alpine Linux をベースイメージに使った公式のPHPイメージを使ってコンテナを作っているのですが、iconvという文字コードを変換する関数がうまく動かずに悩んでいました。

こんなエラーが出てました。

Wrong charset, conversion from `ISO-2022-JP' to `UTF-8//TRANSLIT//IGNORE' is not allowed.

bugs.alpinelinux.org

実際にこれはバグではなく、単にデフォルトで入っているiconvの実装が普通のものと違うことから生じているエラーなようです。

解決策

php-iconv issue | Alpine Linux forums で紹介されている先のDockerfileを参考に最新のiconvのソースをビルドして置き換えることで解決できました。現在の最新のバージョンは1.15なのでDockerfileに以下のコードを加えます。

RUN curl -SL http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz | tar -xz -C ~/ &&\
    rm /usr/bin/iconv &&\
    mv ~/libiconv-1.15 ~/libiconv && \
    ~/libiconv/configure --prefix=/usr/bin && \
    make && make install

ENV LD_PRELOAD /usr/bin/lib/preloadable_libiconv.so

これだけで、PHPは新しく入れた方のiconvを使ってくれるようになりました!

ちなみに古い記事だとiconvのバージョンが1.14の方を使っているものがありますが、新しい Alpine Linuxgccではgets関数がなくなっているのでビルドすることができません。

弊社では一緒にサービスを開発してくれる方を探しています!

一緒に最新の技術でサービス開発しませんか!?

en-gage.net

DockerでPHPのPeclのextensionを入れる方法

f:id:takuseno:20170210182324j:plain

エンジニアアルバイトの妹尾(id:takuseno)です。

今回はDockerの公式PHPイメージでPeclを使ったextension(mailparse)を入れるのに苦労した話をします。

Pecl extensionsの入れ方

公式Dockerイメージを使う場合は、extensionを有効化するためにdocker-php-ext-*という名前のコマンド群が用意されています。

PHP Official Image

PHPにもともと入っているextensionsはDockerfile内で

docker-php-ext-install curl

とすれば入ります。

Peclの場合でもかなり簡単で、memcachedを入れようと思ったら

pecl install memcached
docker-php-ext-enable memcached

で有効にできます。

コンパイルオプションの必要なものはこのままではできない

今回はmailparseというextensionを入れようとしたのですが、ドキュメントを見ると--enable-mailparseというPHPコンパイルオプションが必要だと書いてあったので、上の方法だけでは入りません。

途方に暮れて、公式イメージのDockerfileを眺めていると$PHP_EXTRA_CONFIGURE_ARGSという変数が使われているのを発見しました。

github.com

ここに値を入れれることでオプションを追加することができます。

dockerはバージョン1.9頃から--build-argというコマンドラインオプションを提供しています。

qiita.com

ということでDockerfileには

pecl install mailparse
docker-php-ext-enable mailparse

と書いておいて、build時に

docker build . --build-arg PHP_EXTRA_CONFIGURE_ARGS="--enable-mailparse"

とすることで無事mailparseが使えるようになりました!

弊社ではDockerを使ってサービスを開発したいエンジニアを探しています!

是非一緒にサービス開発しませんか!?

en-gage.net

Googleが昔採用していたバグ予測アルゴリズムをやってみた

f:id:takuseno:20170206174004j:plain

エンジニアアルバイトの妹尾(id:takuseno)です。

今回はGoogleが昔採用していたバグ予測アルゴリズムのもとになっているFixCacheについて書きたいと思います。

バグ予測アルゴリズム

かなり前の記事ですが、こんなものがありました。

www.publickey1.jp

元の記事はこちらです。

google-engtools.blogspot.jp

巨大なコードを一つのリポジトリで管理しているGoogleはバグ予測アルゴリズムによって、レビュー時にどのファイルをより注意深く見るべきかの指標を出していたようです。

アルゴリズムの説明

FixCacheというアルゴリズムについての説明はこの論文に書かれています。

執筆者は UC Davis の方のようです。

ではこのアルゴリズムの説明に入る前にキャッシュについて理解する必要があります。CPUはメモリへのアクセス時にキャッシュを使うことでI/O時間を削減することでより効率的に動作するようになっています。ここで理解するべきキャッシュの特性は、

  1. temporal locality
  2. spatial locality

の二つです。この二つの説明は僕のブログでしていますが、簡単にいうと

  1. 一度アクセスされたデータは近いうちにアクセスされる可能性が高い
  2. 一度アクセスされたデータの周辺にあるデータはアクセスされる可能性が高い

という意味です。

takuseno.hatenablog.com

本題

ではFixCacheのアルゴリズムはどうなっているかというと、バグの発生とこのキャッシュの仕組みになぞらえて考えることができるというものです。先ほどの特性をバグに当てはめて見ると。

  1. 一度バグを修正されたファイルは再び修正される可能性が高い
  2. バグが発見されたファイルと一緒によく編集されるファイルはバグを含んでいる可能性が高い

というふうに言えます。さらに論文ではもう一つの churn locality というものを加えています。これは

  • 最近編集されたファイルはバグがあるかもしれない

という感じです。おそらくこのポリシーはLRU(Least Recent Used)というコンピューターサイエンス用語で、最も最近使われていないものから交換するというキャッシュの更新法のことだと思います。

この3つのポリシーに従ってコミット履歴を見ていくことでバグの予測ができるというわけです。

実際にやって見た結果

コードがどこかにいってしまって載せられないのですが、弊社の古くからあるプロジェクトでコミット修正した基準を、コミットメッセージに修正またはfixという文字が入っているかどうかという基準でやって見たところヒットレートが50%でした。キャッシュに置くファイルの数を全ファイルの20%にしたら良いという記述があった気がするのでそれに従いました。

この結果は結構すごいいい感じかも?と思いましたが、原論文では完璧に評価するには

  1. バグ予測されたがバグはないファイル (FP)
  2. バグ予測されてバグのあるファイル (TP)
  3. バグ予測されてなくてバグのあるファイル (FN)
  4. バグ予測されてなくてバグのないファイル (TN)

を考えた時に精度は

Precision = TP / (TP + FP) = TP / InCache

というふうに考えられるという感じのこととか色々書いてありましたが、これは理論上のお話です。論文中でも実際の評価は普通のヒットレートを使用したようです。

実はもう使われていない

頑張って紹介して見ましたが、このアルゴリズムというよりもバグ予測ツール自体がもう使われていないようです。

このようなバグ予測ツールがエンジニアにとってあまり有益な結果を出さなかったみたいです。

詳しいことはリンク先の論文やサイトを見るとわかると思います。

弊社は今このような話を聞いてワクワクするような人を探しています!

一緒にサービス開発しませんか?!

en-gage.net

GitHubのメンションをDMで教えてくれるボット

f:id:takuseno:20161213175351j:plain

エンジニアアルバイトの妹尾(id:takuseno)です。

この記事はボット・クローラー Advent Calendar 2016の14日目です。

今回はGitHubのメンションをSlackのDMで教えてくれるボットを紹介します。

弊社でのボット

弊社ではHubotをHeroku上で動かしています。以前にもこのブログで紹介しました。

blog.matchingood.com

メンションをDMで教えてくれる機能は初期から用意していました。理由は弊社の開発フローでGitHubの存在が大きくなったのですぐにGitHub上での更新を知る必要が出てきたからです。

blog.matchingood.com

特にメンションはSlackでDMで伝えてくれると開発用のチャンネルの通知を出さないようにしていても通知してくれるのでとても便利であることは明らかでした。

コード

プルリクエストへのレビューコメントのhookに対するコードは簡単に書くと以下のような感じです。

users =
  'takuseno': 'seno'

module.exports = (robot) ->
  robot.router.post "/github/pr/review", (req, response) ->
    data = req.body
    action = data.action
    path = data.comment.path
    user = data.comment.user.login
    url = data.pull_request.html_url
    number = data.pull_request.number
    title = data.pull_request.title
    repo = data.pull_request.head.repo.name
    body = data.comment.body

    if action != 'created'
      response.end ''
      return

    attachment =
      content:
        fallback: body
        pretext: path
        mrkdwn_in: ["text", "pretext", "fields"]
        color: "#f1c40f"
        author_name: users[user]
        title: "\##{number} #{title}"
        title_link: url
        text: body

    mentions = body.match /@(\S+)\s*/
    if mentions?
      for index, name of mentions
        if users[name]?
          userId = users[name]
          robot.adapter.client.openDM userId, (data) ->
            attachment.channel = userId
            robot.emit "slack.attachment", attachment

  response.end ''

ポイントは上記のコードではusersGitHubのユーザー名とslackのユーザー名の対応表を入れておいて、コメントを正規表現でメンションを探してslackに投げているところです。

あとは、DMの見た目を良くするためにattachmentというのを使っています。slackのattachment自体は以下に載っています。

api.slack.com

実際の感じ

f:id:takuseno:20161213174233p:plain

これでGitHub上でのコミュニケーションがよりスムーズになりました!

弊社ではこういう取り組みに興味のあるエンジニアを探しています。一緒にサービス開発をしませんか?

en-gage.net