わすれっぽいきみえ

みらいのじぶんにやさしくしてやる

25日目: GitHub APIを叩いた結果をDBに入れるだけのコマンドを作る その2

kimikimi714.hatenablog.com

の続き。

コマンド引数とメインの処理をちゃんと見直す。

コマンドに渡す引数

Pull Requests | GitHub Developer Guide

にあるようにどのオーナーによる何のリポジトリのpull request情報を取得したいのかを指定すれば良いので

      *
      * @var string
      */
-  protected $signature = 'fetch:github {owner}';
+  protected $signature = 'fetch:github
+                        {owner : Repository owner name}
+                        {repo : Repository name}
+                        {--x|execute : if false, execute this command with dry run mode.}
+                        {--number : Pull Request Number}';
 
     /**
      * The console command description.

Laravelではコマンド引数の説明も上記のようにマルチラインで記載が可能になっている。デフォルトで -h がヘルプオプションになっているので、それを指定して実行すると以下のように表示される。

$ php artisan fetch:github -h
Usage:
  fetch:github [options] [--] <owner> <repo>

Arguments:
  owner                 Repository owner name
  repo                  Repository name

Options:
  -x, --execute         if false, execute this command with dry run mode.
      --number          Pull Request Number
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
      --env[=ENV]       The environment the command should run under
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Help:
  Fetch GitHub Repo data and save DB

メインの処理

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
      if ($this->option('execute')) {
        $this->dryRun = false;
      } else {
        $this->info('Dry run mode.');
      }
      $owner = $this->argument('owner');
      $repo = $this->argument('repo');
      $openPullRequests = $this->client->api('pr')->all($owner, $repo, ['state' => 'open']);
      foreach ($openPullRequests as $pr) {
        $this->line('number: ' . $pr['number']);
        $this->line('title: ' . $pr['title']);
        $this->line('owner: ' . $pr['head']['user']['login']);
        $this->line('url: ' . "https://github.com/${owner}/${repo}");
        if (!$this->dryRun) {
          DB::transaction(function () use ($owner, $repo, $pr) {
            $user = \App\User::firstOrCreate([
              'name' => $pr['head']['user']['login'],
              'email' => 'dummy@example.com',
              'url' => $pr['head']['user']['html_url'],
            ]);
            $review = \App\Review::updateOrCreate([
              'status' => $pr['state'] === 'open' ? 0 : 1,
              'hosting_type' => 'github',
              'repository_url' => "https://github.com/${owner}/${repo}",
              'number' => (int)$pr['number'],
              'title' => $pr['title'],
              'author_id' => $user->id,
            ]);
          });
        }
      }
    }

だいぶ雑にわぁーっと作ったが

  • UserにPR参加者のデータをDBに入れる。
  • ReviewにPRのデータをDBに入れる。

をまさにやってる。

dry-runの判定部分をメインの処理の中に本当は書きたくなかったんだが

Illuminate\Console\Command | Laravel API

を見てもbeforeとかinitializeとかないし、まぁこんなもんかな?と思って一旦書いた。

usersテーブルへのinsertはレコードがなかったら作るの firstOrCreate を、 reviewsテーブルは INSERT...ON DUPLICATE KEY UPDATE に当たる updateOrCreate を利用している。

割りとdoctrine ORMの使い方と似てる *1 ので使ったことのある人なら、そんなに抵抗なく使えるかもしれない。

このコマンドのままだとopenなPRしか取ってこれない。このため、本来はreviewsテーブルにある、まだstatusがopenになってるレコード全部に対して取得の必要があるし、コメントがまだ取ってこれない。 あと、0とか1とかモロにマジックナンバーが書いてあるので、ちょっとConstクラスかなんか作って隠蔽したい。

けど、今日はここまで。

*1:というか私が真面目にコードベースに何使ってるか追いかけてないだけ。doctrine/dbal をcomposerで入れないとmigrationsだけでは使えない機能があったりするので無関係ではないと思う