Qiita や自分のブログに GitHub のリポジトリのリンク貼ってもなんか寂しいからいい感じのカードっぽいやつ生成するやつを作ったって話です. iframe で埋め込むことができます。

だがしかし!Qiita などに任意の iframe が埋め込めるわけないジャーーーン!

ということに,だいたい完成してから気づいた orz

GitHub Card

特別定義はないけど,こんな感じのを iframe で作りたかった.

作る

マイフェィバリット JS 系プログラミング言語 Elm を使った. だいたい半日ぐらいかかった.GWの最終日.GW最高. リポジトリはこれ:

GitHub Pages に置いたので誰でも試せる. ただし,裏では GitHub API v3 をトークンなしで叩いてる...

こんな感じになる:

上がユーザーのカードで下がリポジトリのカード. Embed: の下に書いてある iframe タグをコピペすることで埋め込める.

ちょっとした工夫

Elm の Browser.application の URL 機能をわざわざ使って色々工夫してる:

  • https://xxxx#name とすることで直接任意ユーザー/リポジトリのカードのページを開ける
    • 実は Build ボタンで #name にジャンプしてる笑
  • https://xxx?target=name とすることで name のカードだけを表示
    • iframe にはこっちを使う
  • getElementById とかわざわざしてぴったりの widthheight を iframe に生成してる

問題点

上述した通り,GitHub API をトークンなしで利用しているので rate limit がある(同一アドレスから60req/h). 開いた人によってはページが見れないのは悲しい...

作る(パート2)

ウンウン考えながら帰宅してたら気づいた. どーせ GitHub のユーザーやリポジトリのステータスなんてコロコロ変わるもんでもないし,適当に JSON で吐いておいて毎日更新する CI でも回しておけば良くない?? と.

ということで、思いついてしまったので作ってしまった. 気づいたら朝4時.GW延長戦(????).

できたもの

集める部分と表示する部分を分けた:

前回の matsubara0507/github-card と違い自分専用. selfcat という CLI ツールで次のような設定ファイル .selfcat.yaml にあるユーザーとリポジトリの情報を収集(GitHub API v3)し,JSON として保存する. もちろん Haskell 製.

owner: matsubara0507
repos:
- mix.hs
- selfcat

--compact オプションをつけることで一つの JSON にまとめてくれる. my-github-cards の方は selfcat を使って一つにまとめて生成した JSON ファイルを読み込んで GitHub Card を表示する. 表示した見た目は前回のと同じ.

selfcat

これはやってること単純:

  1. 設定ファイルの YAML を読み込み (yaml パッケージ)
  2. GitHub API を叩き (github パッケージ)
  3. JSON を吐くだけ (aeson パッケージ)

例のごとく,rio + extensible でサクッと作った.

中身を見るとわかるのだが mix というパッケージを使っている. これは rio + extensible のいつも自分が使うパターンをパッケージ化したもの. そのうちまたまとめます.

生成した JSON ファイルを読み込む

Elm で「生成した JSON ファイルを読み込む」というのは少し大変だった. Elm で初期値を与えるには init 関数の Flag というのを使う。このあたりが参考になる

で,問題はどうやってローカルの JSON を読み込むか. git-plantation では Haskell で埋め込んでいたのだが,今回はサーバー側がないのでできない. ググったら出てきた:

JS 詳しくないのでこれが良い方法なのかはわからないけど,これを参考にして次のような JS を書いて index.html から読み込むようにした:

"use strict";

function loadJSON(callback) {
   var xobj = new XMLHttpRequest();
       xobj.overrideMimeType("application/json");
   xobj.open('GET', 'static/info.json', true);
   xobj.onreadystatechange = function () {
         if (xobj.readyState == 4 && xobj.status == "200") {
           callback(xobj.responseText);
         }
   };
   xobj.send(null);
}

loadJSON(function(response) {
  var json = JSON.parse(response);
  Elm.Main.init(
    { node: document.getElementById('main')
    , flags: { info: json }
    }
  );
});

少なくとも,うまく動作はしている.

いつも通り,GitHub Pages に置いたのでここから見れる. というか,さっきから表示している GitHub Card がこれで埋め込んだものだ.

Daily cron on TravisCI

更新は TravisCI の Daily cron を使う. selfcat は Docker Image にしたので selfcat をビルドする必要はない. docker run で JSON を生成し,差分があったら GitHub に push する.

知らぬ間に,TravisCI の設定方法に deploy という設定が増えていたんですね:

# .travis.yml
language: generic
services:
  - docker

before_install:
- docker pull matsubara0507/selfcat

jobs:
  include:
    - stage: exec selfcat
      if: branch = master
      script: docker run --rm -e GH_TOKEN -v `pwd`:/app matsubara0507/selfcat bin/bash -c 'cd app && selfcat --output=docs/static/info.json --compact .selfcat.yaml'

deploy:
  - provider: script
    skip_cleanup: true
    script: bash .travis/deploy.bash
    on:
      branch: master

deploy のところで読んでいるスクリプトは以下:

#!/bin/bash
set -eux

# setup ssh-agent and provide the GitHub deploy key
eval "$(ssh-agent -s)"
openssl aes-256-cbc -K $encrypted_3b94903f5871_key -iv $encrypted_3b94903f5871_iv -in .travis/id_rsa.enc -out .travis/id_rsa -d
chmod 600 .travis/id_rsa
ssh-add .travis/id_rsa

# commit the assets in docs/ if changed, and push to GitHub using SSH
git config user.name "${GIT_NAME}"
git config user.email "${GIT_EMAIL}"
git remote set-url origin git@github.com:${TRAVIS_REPO_SLUG}.git

git checkout master
git status
git add docs
git diff --staged --quiet || git commit -m "[skip ci] Update docs by selfcat"
git push origin master

GitHub の Personal Access Token を使うのが嫌なので deploy key を登録して,暗号化したものをリポジトリに置き,それを CI の中で複合して使うという方法をとっている. ググったら下記の記事が出てきてそのまま使わせてもらった:

暗号化/複合の部分は TravisCI の Encrypting Files を使うことで簡単に行える. 記事で1点,スクリプトの呼び出しが script: ./.travis-deploy.sh では呼べなかった. ググったら Issue があり,script: sh deploy.sh とすれば良いみたいだったのでそうしたらうまくいった.

ちなみに,matsubara0507/my-github-cards をフォークして,selfcat と TravisCI の設定(.travis/id_rsa.enc と環境変数など)を変えれば誰でも my-github-cards を使える. 気が向いたらドキュメントにしよ.

ToDo

  • 入力してエンターキーで Build ボタン押したことにしたい
  • Embed のところにクリップボードにコピーボタン欲しい

あと,特に Elm はやっつけで書いたので全体的にコードが汚い気がする.

おしまい

自分(self)の GitHub (Octocat)の情報を集めるから selfcat です(????)。