くりにっき

フルスタックキュアエンジニアです

omniauth-chatworkを作った

github.com

なんのgem?

最近ChatWorkでOAuth認証に対応したのですが、それに対応したomniauthのproviderです

使い方

OAuthクライアントの登録

まず最初に下記を参考にOAuthクライアントを作ってください

developer.chatwork.com

blog-ja.chatwork.com

この時リダイレクトURIhttps://〜/outh/chatwork の形式にしてください。

f:id:sue445:20171116165200p:plain

https://127.0.0.1:4567/ も登録しているのはローカルでの確認用です。

余談ですが2週間位前に https://localhost:4567/ で登録しようとすると「https://example.com形式で登録してください」的なエラーが出たのでその時は https://127.0.0.1:4567で登録して回避しました。

今確認したら https://localhost:4567/で登録できるようになっていたので今はどっちでもいいと思います。

omniauth-chatworkをproviderとして組み込む

あとは omniauth-facebookomniauth-twitter と同様に下記のような感じでproviderを登録してください

use OmniAuth::Builder do
  provider :chatwork, ENV["CLIENT_ID"], ENV["CLIENT_SECRET"]

  # scopeを明示的に指定したい場合はこっち
  provider :chatwork, ENV["CLIENT_ID"], ENV["CLIENT_SECRET"], scope: ["users.all:read", "rooms.all:read_write", "contacts.all:read_write"]
end

確認してないけどRailsなら config/initializers/omniauth.rb をこんな風に書いておけばたぶん動きます。

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :chatwork, ENV["CLIENT_ID"], ENV["CLIENT_SECRET"]
end

技術的なこと

ローカルでのSSL確認時はwebrick使うのが便利だった

http://developer.chatwork.com/ja/oauth.html にも書いてますがリダイレクトURIhttpsである必要があります。これは当然ローカルでの確認時にもhttpsが要求されます

ググるHTTPS証明書を作成してローカルで起動したApacheに喰わせて云々っていう記事が出ますが、Rubyならwebrickで下記のような設定を書いておけば起動時にオレオレ証明書を動的生成してくれるのでそんな心配はありません

set :server_settings,
    SSLEnable: true,
    SSLCertName: [["CN", WEBrick::Utils.getservername]]

https://github.com/sue445/omniauth-chatwork/blob/v0.1.0/spec/dummy/app.rb

実際ローカルでOAuth認証確認する時はomniauth-chatworkのリポジトリをcloneして bundle exec ruby spec/dummy/app.rb で動きます

参考資料

omniauth provider作成時に参考にしたもの

今までOAuth2のクライアントライブラリ使わずにゴリゴリ自前実装してきたので、omniauthのルールに則ってgemを作るってのが新鮮でした

追伸

SAML連携してるChatWorkアカウントだとOAuth認証が非常に分かりづらいのでそれはまた後日書きます

-> 書いた

sue445.hatenablog.com

wercker_build_triggerを作った

github.com

wercker_build_triggerについて

Wercker のビルドを外部から手軽に実行するためのツールです

モチベーション

僕は下記のように週1回Travis CIで定期ビルドを実行しています

sue445.hatenablog.com

WerckerでCI回してるリポジトリでも定期ビルドをやりたかったのですが、WerckerではTravis CIのCron jobsのような機能がなかったのでcrontabから実行しやすくするためにツールを作りました。

使い方

golang製なので https://github.com/sue445/wercker_build_trigger/releases からバイナリを落としてきて適当な場所に置いてください。

設定ファイルはこんな感じ

pipelines:
  - application_path: "wercker/docs"
    pipeline_name: "build"
    branch: "master"
  - application_path: "sue445/wercker_build_trigger"

application_pathは必須。pipeline_namebranchは省略可。pipeline_name省略時はbuildが、branch省略時はmaster が使われます

crontabにこんな感じに書いておけば毎週日曜の3:00に実行されます。

0 3 * * 0 /path/to/wercker_build_trigger --config /path/to/wercker_build_trigger.yml --token xxxxxxx

tokenは https://app.wercker.com/profile/tokens で生成したやつを貼り付けてください。

導入事例

実際に使ってる設定ファイル。

pipelines:
  - application_path: "sue445/itamae-plugin-recipe-omori_gohan"
  - application_path: "sue445/itamae-plugin-recipe-tmux"
  - application_path: "sue445/itamae-plugin-recipe-tig"
  - application_path: "sue445/itamae-plugin-recipe-git_now"
  - application_path: "sue445/itamae-plugin-resource-encrypted_remote_file"
  - application_path: "sue445/itamae-plugin-recipe-consul"
  - application_path: "sue445/capistrano-itamae"
  - application_path: "sue445/wercker_build_trigger"

wercker_build_trigger自身の定期ビルドもwercker_build_triggerで行っています。(ややこしい)

実行結果

[application_path:sue445/itamae-plugin-recipe-omori_gohan][pipeline_name:build][branch:master] Triggered pipeline: https://app.wercker.com/api/v3/runs/59d9a54714816100010bd46f
[application_path:sue445/itamae-plugin-recipe-tmux][pipeline_name:build][branch:master] Triggered pipeline: https://app.wercker.com/api/v3/runs/59d9a54814816100010bd477
[application_path:sue445/itamae-plugin-recipe-tig][pipeline_name:build][branch:master] Triggered pipeline: https://app.wercker.com/api/v3/runs/59d9a5492535040001c453c2
[application_path:sue445/itamae-plugin-recipe-git_now][pipeline_name:build][branch:master] Triggered pipeline: https://app.wercker.com/api/v3/runs/59d9a54a8e888f0001b7de36
[application_path:sue445/itamae-plugin-resource-encrypted_remote_file][pipeline_name:build][branch:master] Triggered pipeline: https://app.wercker.com/api/v3/runs/59d9a54c8e888f0001b7de3e
[application_path:sue445/itamae-plugin-recipe-consul][pipeline_name:build][branch:master] Triggered pipeline: https://app.wercker.com/api/v3/runs/59d9a54d14816100010bd47f
[application_path:sue445/capistrano-itamae][pipeline_name:build][branch:master] Triggered pipeline: https://app.wercker.com/api/v3/runs/59d9a54e8e888f0001b7de46
[application_path:sue445/wercker_build_trigger][pipeline_name:build][branch:master] Triggered pipeline: https://app.wercker.com/api/v3/runs/59d9a54f2535040001c453ca

ビルド結果はSlackに流すようにしてるのでこんな風に通知されます

f:id:sue445:20171008131301p:plain

DigitalOceanで使えるimageを一覧で取得する

tl;dr;

https://gist.github.com/sue445/dd1ab749f9cf364777acbe66d34576e4

前置き

itamaeプラグインのCIを回してたら DigitalOceanで「centos-7-0-x64なんてイメージはないぞ!」ってエラーになりました

+ vagrant up centos70 --provider=digital_ocean
Bringing machine 'centos70' up with 'digital_ocean' provider...
==> centos70: Using existing SSH key: wercker-itamae-plugin-recipe-consul
There was an issue with the request made to the DigitalOcean
API at:

Path: /v2/droplets
URI Params: {:size=>"512MB", :region=>"nyc3", :image=>"centos-7-0-x64", :name=>"itamae-consul-centos70-59d3b5938e888f0001b27d75", :ssh_keys=>[1874082], :private_networking=>false, :ipv6=>false}

The response status from the API was:

Status: 422
Response: {"id"=>"unprocessable_entity", "message"=>"You specified an invalid image for Droplet creation."}

Vagrabtfileだと下記のように provider.image で設定してたのですが、どうも消えた模様。

  config.vm.define :centos70 do |c|
    c.vm.box = "centos/7"
    c.vm.provider :digital_ocean do |provider, override|
      provider.image = "centos-7-0-x64"
    end
    c.vm.hostname  = 'itamae-consul-centos70'
    c.vm.hostname  += "-#{ENV['WERCKER_RUN_ID']}" if ENV['WERCKER_RUN_ID']
  end

実際に使えるイメージ一覧を自分のgistには乗っけてはいたんですが、ググれる場所にあった方が便利なのでブログに記載

使い方

はじめに https://cloud.digitalocean.com/settings/api/tokensAPIトークンを取得

f:id:sue445:20171004203142p:plain

あとはこんな感じに実行したらjsonがとれます。下記のslugをVagrantfileに渡してやればよさそう

$ export DIGITALOCEAN_ACCESS_TOKEN="xxxxxxxxxxxxxxx"
$ curl -s "https://api.digitalocean.com/v2/images?filter=global&per_page=100" -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN" | jq .

{
  "images": [
    {
      "id": 27983450,
      "name": "1520.4.0 (beta)",
      "distribution": "CoreOS",
      "slug": "coreos-beta",
      "public": true,
      "regions": [
        "nyc1",
        "sfo1",
        "nyc2",
        "ams2",
        "sgp1",
        "lon1",
        "nyc3",
        "ams3",
        "fra1",
        "tor1",
        "sfo2",
        "blr1"
      ],

slugで検索したい場合はこんな感じ

$ curl -s "https://api.digitalocean.com/v2/images?filter=global&per_page=100" -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN" | jq -r ".images[].slug" | grep centos
centos-6-5-x32
centos-6-5-x64
centos-6-x32
centos-6-x64
centos-7-x64

jsonはここに置いてるのでページ内検索でも探せます

https://gist.github.com/sue445/dd1ab749f9cf364777acbe66d34576e4

gitlab_mr_release v1.0.0をリリースした

github.com

ふと GitLab APIのドキュメント を読んでたら GET /projects/:id/merge_requests で複数のiidを渡してまとめてMRを取得できるようになってることに気づき、(APIの実行回数的な)N+1問題を解決できそうな気がして改修。 *1

あと、この辺の仕様がAPI v3とv4で微妙に違っていて両方対応するのも面倒だったのでv3を切り捨ててv4のみで動くようにしてます。

v3で動かそうとすると下記のようなエラーになるので注意

$ gitlab_mr_release create
GitlabMrRelease::InvalidApiVersionError: 'https://gitlab.com/api/v3' seems not to be GitLab API v4+. gitlab_mr_release requires GitLab API v4+

詳しくは https://github.com/sue445/gitlab_mr_release/blob/master/CHANGELOG.md 読んで下さい

*1:gitlab_mr_releaseを作った当時はiidは1つずつしか渡せなかった気がする

CIのバッジを並べて表示するだけのサイトを作った

https://sue445.github.io/my-ci-badges

github.com

モチベーション

gemやアプリなどを40個くらいメンテしてて一応全てでweekly ビルドを実行してるのですが、CIのバッジが各リポジトリにしか貼っていなくてCIのステータスをまとめて見るためのポータルサイトが欲しかったので作りました。*1

製作時間半日くらい

f:id:sue445:20170917172732p:plain

使ってる技術

  • Bootstrap v4.0.0-beta
    • いつものようにbootstrap使おうと思ったら4系が出てたので雑に投入
  • Vue.js
    • 「いつもMithril.js を使ってるのでたまには違うのを使うか」っていう雑な理由でVue.jsを採用

デプロイ周り

GitHub Pagesを使ってるのでGitHubにpushするだけ。CIいらずで楽

*1:ビルド結果も個人Slackに全部流してるんだけどさすがに40個同時だとログが流れて気づかないことがたまにある

tweet_sanitizerというgemを作った

退院後の初gem情報です

github.com

どんなgemか?

Twitter APIで取得したツイートの内容から

  • full_text (140文字より長いツイート)があればそれを積極的に使う
  • 短縮URLの t.co を元のURLに戻す
  • ツイートの末尾に含まれてる添付画像などのURLを除去
  • ><&gt;&lt; などにエスケープされているので、エスケープを解除

などのサニタイズ処理を行います

モチベーション

Twittodon のロジックをgem化しています

sue445.hatenablog.com

twittodonのツイートのサニタイズ周りの処理にバグがあったんですが、

という理由でgem化してテストコードをリファクタリングしつつバグ修正しました *1

使い方

tweet_sanitizerを使わない場合

普通に twitter のgemを使った場合

tweet = @client.status("https://twitter.com/github/status/866677968608927744")
tweet.text
#=> "Introducing GitHub Marketplace, a new place to browse and buy integrations using your GitHub account.… https://t.co/dK0Tmcmm72"

tweet_sanitizerを使った場合

using TweetSanitizer::TwitterExtension

extended_tweet = @client.status("https://twitter.com/github/status/866677968608927744", tweet_mode: "extended")
extended_tweet.sanitized_text
#=> "Introducing GitHub Marketplace, a new place to browse and buy integrations using your GitHub account. https://github.com/blog/2359-introducing-github-marketplace-and-more-tools-to-customize-your-workflow"

using TweetSanitizer::TwitterExtension すると生える #sanitized_text でいい感じにサニタイズできます

ツイート取得時の tweet_mode: "extended" がないと前述の full_text がレスポンスで返ってこないので必須です

#status メソッド以外でもツイートを取得しそうなAPI#search とか)のオプションに tweet_mode: "extended" を渡せばたいてい対応してます

参考

Upcoming changes to Tweets — Twitter Developers

詳しくはREADME読んでください

ユースケース

APIで取得したツイートをmastodonなど他のツールに流したり、DBに保存したいような場合に便利かもしれません

入院中に持っていってよかったもの

突然ですが持病が悪化して2週間ほど入院していました

入院時に個人的に持っていってよかったものなどをシェアしたいと思います。おみまいに持っていく品物の参考にしてください

前提

  • 自分が入院してた病院はそこそこ大きかったので、入院生活に必要な日用品はだいたい売ってた
  • 前回入院したのと同じ病院(いわゆるリピーター)なので、売店に売ってないものをピックアップして持っていった
  • 病院内は基本的に自分のテザリング以外のネットは使用不可
    • 自分が入院してた病院では差額料金でネット付きの病室もあったんだけど、どんなネット環境なのかは不明
    • 自分の場合月7GB制限があったので極力テザリングには頼りたくなかった

持っていってよかったもの

Kindle Paperwhite 32GB、マンガモデル

Kindle Paperwhite 32GB、マンガモデル、Wi-Fi 、ブラック

Kindle Paperwhite 32GB、マンガモデル、Wi-Fi 、ブラック

ぶっちぎりでコレ。普通のpaperwhiteだと4GBしかないけど、こいつは唯一の32GBモデル。カタログスペックで700冊保存可能。

入院前日に「これはこのままいくと入院するだろうな」と予感はしてたので、一晩かけて自宅Wi-Fiで300冊近い漫画を全部DLしていました。

前述の通り病院でネットは頼れないので、ローカルに全部保存できるだけの大容量は超重要

ちなみに入院中に

を読んでいました。

病院の消灯は21時だったのですが、Kindleのバックライトを落とせば消灯中でも周りに迷惑かけることなく本を読めたのは良かったです。

ちょっと意外だったのはKindleがネットにつながってないと本を読み終わった後の続刊の表示が出なかったこと。

ノートPC

体調がいい時は手持ちのiPhoneテザリングしてたまにコード書いてました

ちなみに入院時に書いてたコードはこちらになります。両方ともマージされてるのでGitLab v9.5.0でリリースされるはず。*1

余談ですがGitLabのリポジトリが大きすぎて(おそらく1GB超え)テザリングでcloneしたらパケ死しかけました。リポジトリくらいは家でcloneしとけばよかったかなぁw

f:id:sue445:20170811152229p:plain

うちわ

f:id:sue445:20170811152607j:plain

集団病室だと体温調整がしづらいのでうちわを持っていって正解でした。大して荷物にならない上に、あると何かと便利

ちなみに上のうちわは先日 長谷川町子美術館サザエさん展に行った時にもらったうちわです。

タップ

病室内は1人で使えるコンセントの数に限りがあるので分岐できるタップがあると重宝

あと、長めの延長コードが1本あればベッドの中からスマホ操作できるので便利

ポータブルテレビ

病院内のテレビはカード制(自分が入院してたところは1000円で2時間)だったので、ポータブルテレビ持ってるのであれば持ってった方がいいです

ワンセグ受信アダプタ DSテレビ

ワンセグ受信アダプタ DSテレビ

ちなみにDSテレビは10年くらい愛用していますが、いまだにTVの旅をコンプしていません

f:id:sue445:20170811153829j:plain

イヤホン

自分が入院した病院はテレビ見るのにイヤホン必須でした。売店に売ってはいたんだけど普段使いのイヤホンの方がよかったので持っていってよかったです

病院で買ったもの

耳栓

入院時に隣の人のいびきがうるさくて眠れなかった時があったので、買っといてよかった

買っておけばよかったもの

アイマス

消灯後もたまに同室の別の患者さんの点滴交換とかで(全部じゃないけど)電気がついてその度に目が覚めてたので、買っとけばよかったかなと後悔

【追記】持っていけばよかったもの

New3DS LL

DSテレビ用のDSi LLは持って行ってたのですが、New3DSも持っていけばよかったかなぁと後悔。*2

VCなどのDL済ソフトがいくつか入ってたので暇つぶしにはなったはず。

ドラクエ11の発売直後だったので家でDLして入院中にプレイするという選択肢もあった

おまけ1: 病院食変遷

入院1~7日目

お茶と水はOKだったけどご飯食べていません(´・ω・`)

入院8日目の病院食

f:id:sue445:20170807122428j:plain

8日目にして食事解禁。

こんな流動食ですが1週間絶食後だったのでむちゃくちゃ嬉しかったです

入院12日目(最終日)の病院食

f:id:sue445:20170811122220j:plain

途中で五分粥を経由して全粥までランクアップ

慣れると病院食も美味しいんですが、いかんせん消化がよすぎてすぐにお腹が空くのが難点

おまけ2: 8月のパケット利用状況

f:id:sue445:20170811154750p:plain

7/31~8/11まで入院してたので、↑は実質8月分のパケット使用量

残り0.22GB、いろいろとヤバかった。

まったく、家のWi-Fiは最高だぜ!

*1:この修正が本家に取り込まれないと自作ツールでGitLab API v4対応できなかったので、入院中でも対応する必要があった

*2:だったら最初からNew3DS LL + DSテレビ装備にすればええやんっていうツッコミもありそうなのですが、New3DS LLはスロットの形状の関係でDSテレビがささらないのです