くりにっき

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

Itamae v1.10.0をリリースした

リリースノート

https://github.com/itamae-kitchen/itamae/blob/master/CHANGELOG.md#v1100

今回の差分は1つだけですが、個人的には目玉機能だと思ってます。

Support only_if and not_if inside a define

github.com

v1.9.xまで

みんな大好き define *1 ですが、define の呼び出しの中では only_ifnot_if が使えなくて define の実行自体をスキップするには下記のように外部から無理やり条件を渡すしかありませんでした

define :install_and_enable_package, version: nil, only_if: nil do
  v = params[:version]
  only_if_condition = params[:only_if]
  package params[:name] do
    version v if v
    action :install
    only_if only_if_condition
  end

  service params[:name] do
    action :enable
    only_if only_if_condition
  end
end

install_and_enable_package "nginx" do
  only_if "ls /tmp/install_eginx"
end

v1.10.0以降

define の呼び出しの中で only_ifnot_if を使えるようにしたので、今までのようなハックは不要になり下記のように他のリソース同様シュッと書けるようになります。

define :install_and_enable_package, version: nil do
  v = params[:version]
  package params[:name] do
    version v if v
    action :install
  end

  service params[:name] do
    action :enable
  end
end

install_and_enable_package "nginx" do
  only_if "ls /tmp/install_eginx"
end

既存のレシピやプラグインの中でdefineを多用している場合はv1.10.0に上げることでリファクタリングできるようになると思われます。

*1:要出典

CircleCI 2.1のorbを作って最速で実アプリに投入した

tr;dr;

【前置き】先日の出来事

2.1 preview自体は結構前から出ていたのですが、先日正式リリースされました

orbとは

  • .circleci/config.yml をモジュール化する仕組み
    • 複数リポジトリで共通する処理を1箇所に集約できる
    • 自分が作ったorbを配布もできる
  • WerckerでいうところのStep Marketplace
  • GitLabCIには以前からStarter以上(有料プラン)では使えていたが、v11.4でCore(無料プラン)でも使えるようになった

【今回作ったもの】sue445/ruby-orbs

個人アプリ10個くらいCircleCIを使っているのですが、全部CircleCI 2.1にアップデートしてこのorbを導入しています

モチベーション

  • CircleCIでキャッシュをいい感じに利用しつつbundle install するにはコツがいる
    • どれくらいコツがいるのかというとCircleCIのcache key戦略だけでエントリ1つ書けるくらい
  • アプリ作る度に下記のような設定を毎回コピペするのが苦痛(10リポジトリくらいある)

.circleci/config.yml

save_bundle_cache_option: &save_bundle_cache_option
  key: v1-bundle-{{ checksum "Gemfile.lock" }}
  paths:
    - ~/app/vendor/bundle

restore_bundle_cache_option: &restore_bundle_cache_option
  keys:
    - v1-bundle-{{ checksum "Gemfile.lock" }}
    - v1-bundle

jobs:
  rspec:
    <<: *default

    steps:
      - checkout
      - restore_cache:
          <<: *restore_bundle_cache_option
      - run: ./.circleci/setup_bundle.sh
      - save_cache:
          <<: *save_bundle_cache_option

      - run: bundle exec rake test

.circleci/setup_bundle.sh

#!/bin/bash -xe

bundle install --jobs=4 --retry=3 --path vendor/bundle
bundle clean

# Resolve bundler version difference between Gemfile.lock and pre-installed in CI
gem install restore_bundled_with --no-document
restore-bundled-with

そこでこの機会に今までの知見をorbにしました

準備

organizationの設定で3rdパーティ製orbを有効にしておく必要があります。(デフォルトOFF)

f:id:sue445:20181110161451p:plain

また、リポジトリのAdvanced SettingsでEnable build processingがOffのままだと現時点だと2.1の記法が解釈できなくてvalidate errorになったので、ここもOnになってるか確認しましょう

f:id:sue445:20181110161737p:plain

使い方

.circleci/config.yml に下記のようなのを書くだけです

version: 2.1

orbs:
  # Use specific version
  # see. https://github.com/sue445/circleci-ruby-orbs/releases
  ruby-orbs: sue445/ruby-orbs@1.1.2

  # or
  # Use latest version
  # ruby-orbs: sue445/ruby-orbs@volatile

jobs:
  rspec:
    steps:
      - checkout

      - ruby-orbs/bundle-install
      # or
      - ruby-orbs/bundle-install:
          cache_key_prefix: "v1-bundle"
          bundle_jobs: 4
          bundle_retry: 3
          bundle_path: "vendor/bundle"
          bundle_clean: true
          bundle_extra_args: ""
          restore_bundled_with: true

      # Add your job (e.g. rspec, rubocop)
      - run: bundle exec rspec

補足

現時点ではGemfile.lockがコミットされてるリポジトリのみサポートしています。(具体的にはgemみたいにGemfile.lockをコミットしていないリポジトリでは使えない)

理由

  • CircleCIのキャッシュのキーにGemfile.lockのチェックサムを利用してるため
  • gemのCIでCircleCIを使ったことはあるが、色々考慮することがある&仕組が複雑になるので自分の中でベストアンサーがまだ見つかってないので作りかねてる

CircleCI 2.0から2.1に移行したPR

手持ちのアプリ10個くらい全部CircleCI 2.1対応したので、そのうちPRを1つだけ紹介します

Migrate to circleci 2.1 by sue445 · Pull Request #334 · sue445/sebastian-badge · GitHub

差分を見てもらえれば分かると思いますが、記述が大幅に減っています

ついでにHerokuにデプロイするやつもorbに寄せた

https://github.com/CircleCI-Public/circleci-orbs/tree/master/src を見てたらHerokuデプロイ用のorbもあったので導入しました

https://circleci.com/orbs/registry/orb/circleci/heroku

Before

After

補足

post-deploy

  • CircleCI 2.1だとstepを引数として受け渡しできるため、orbの処理は使いたいが特定の場所に任意の処理を差し込みたいということができる
  • 今回の場合、heroku/deploy-via-gitpre-deploypost-deploy というフックポイントを引数で用意しているので、デプロイ後に heroku run rake ar:migrate するために post-deploy を使ってる

Context

  • Herokuにdeployする時の $HEROKU_API_KEY をcontextで定義してると、同じ環境変数を各リポジトリの設定のEnvironment Variablesではなく、organizationの設定1箇所に集約できて便利
    • 2.1の新機能ではなく(たぶん)2.0時代からあった
  • Herokuのパスワード変えたり二段階認証ON/OFFするとAPI Keyも再発行されるので1箇所で集約されてると何かと便利
  • heroku/deploy-via-git もデフォルト値は環境変数$HEROKU_API_KEY から取ってきてた

f:id:sue445:20181110163549p:plain

one more thing

  • 今回作ったorbのインテグレーションテストも頑張ってるのですが、長くなるので別の機会に書こうと思います
    • どれくらい頑張ってるのかというと、orbのインテグレーションテストとその周辺技術だけで30分くらい話せるボリューム

追記:2018/11/16

書いた

sue445.hatenablog.com

pry-docにPRを投げた

pry v0.12.0で色々deprecationになって関連gemでもdeprecation warningが出るようになってたので、PRチャンスということで投げました

https://github.com/pry/pry/blob/master/CHANGELOG.md#v0120-november-5-2018

pry-doc v0.13.5

PR 2つともわたしです ^q^

Fixed deprecation warnings emitted by Pry v0.12.0

github.com

pry v0.12.0のdeprecation warning対応

Fixed MRI 2.0 regression

github.com

87のPR投げたらRuby 2.0でCIコケてたのでついでに直した

メンテナがRuby 2.0のkeywoard argsとRuby 2.1のrequired keyword argsを勘違いしていたので説明するのが大変だった・・・

https://github.com/pry/pry-doc/pull/88#discussion_r231043234

Itamae v1.9.13をリリースした

CHANGELOGに載ってる修正

https://github.com/itamae-kitchen/itamae/blob/master/CHANGELOG.md#v1913

Fixed. Can not create empty file

github.com

fileリソースで空ファイルを作れないバグの修正。

github.com

元々remote_fileやtemplateで空ファイル作れていたのですが、いつのバージョンからか作れなくなっていたのを前職時代に観測してました。

その時は execute "touch xxx"で雑に回避してたのですが、今回mitamaeと同じ修正を入れて解決しました。

CHANGELOGに載ってない修正

Fixed rspec warning

github.com

travisのweekly buildのログを見てたら

expect {
  subject.event(:name, :arg) { raise "name is failed" }
}.to raise_error

でwarning出ていたのを直しました。

Fixed. test is failing after run test

github.com

これ英語が怪しいんだけど、要はローカルで開発してる時に同じコンテナに対して同じレシピを2回適用するとItamaeがコケるという現象があって直しました。

-execute "mkdir /tmp/link-force-no-dereference1"
+execute "mkdir -p /tmp/link-force-no-dereference1"
 link "link-force-no-dereference" do
   cwd "/tmp"
   to "link-force-no-dereference1"
   force true
 end

Pixelaで自分のツイート数を草化した

こんな感じです。

pixe.la

リポジトリ

github.com

仕組み

Twilogスクレイピングして、CircleCIのcronの仕組を使って定期的(当日分は1時間おき、前日分は1日1回)にツイート数をグラフを更新しています。

スクリプトRubyで書いていますが、定期実行部分に関してはCircleCIとDockerイメージだけで完結しているので実行環境にRubyをインストールする必要はありません。

追記:2018/11/26

1時間おきは多すぎた感があったので今は6時間おき(1日4回)にしてます

Twilogを使ってる理由

  • 特定の日時のツイート数だけを取得するだけならTwitter APIよりTwilogからとってくる方が早いし楽
    • Search APIでも日付を絞り込むことはできるのだが、自分の経験上たまに検索結果が取れなくなることがあるのであまり信用してない *1
    • 特定のユーザのツイートを取得するならuser timeline APIを使うのが確実なのだが直近3200件分しかとれない。
      • 当日分と前日分くらいなら問題ないんだが、それでもuser timetimeで特定の日付を絞ってツイートを取得するのは若干面倒
    • 過去分を一括投入しようとするとRateLimitに引っかかってしまう
    • Twilogであれば https://twilog.org/sue445/stats に全期間(自分が登録した以降全部)のツイート数が入ってるので、何回もAPIを叩くよりもhtmlを1枚スクレイピングする方が圧倒的に楽と判断
  • Twitter APIだと自分でアプリ(APIをたたくためのアクセストークン)を作る必要があってお手軽感がない
  • 過去分投入だけなら公式のツイートダウンロードでもいいんだけど、OSSとして公開しようとすると英語で説明を書くのが面倒だしスクリプト化しづらい

使い方

基本的には https://github.com/sue445/tweet_pixels/blob/master/README.md に書いてる通りにコマンドを実行するだけ。

最初のPixela登録とグラフ作成だけローカルで実行する必要があります。

Rubyでやりたい場合は https://github.com/sue445/tweet_pixels をforkしてclone後に下記のようなコマンドを実行してください。

cp .env.example .env
vi .env
bundle install --path=vendor/bundle

./bin/console
# register
@client.create_user(agree_terms_of_service: true, not_minor: true)

# create graph
@graph.create(name: "Daily tweets", unit: "Tweets", type: "int", color: "sora")

他言語の場合は同じようなことをよしなにやってください。

直近1年分のツイートを一括投入する場合は bundle exec rake update_multi を実行

グラフ作成後はCircleCIのEnvironment Variablesに

  • TWITTER_ID
  • PIXELA_USERNAME
  • PIXELA_TOKEN
  • PIXELA_GRAPH_ID

を登録してください。

f:id:sue445:20181021110424p:plain

Tips

CircleCIでボットを運用する時のノウハウとして、Chat Notificationsで普段使いのチャット(自分の場合Slack)を登録しておくとエラー時にすぐに気付けるので便利です。

f:id:sue445:20181021110928p:plain

1時間に1回にSlackに通知がくると逆にウザいので、自分はFixed/Failed Only(ビルドが失敗から成功に戻った時と、ビルドが失敗した時のみ通知)をよく使っています。

所感

今回のに限ったことじゃないんだけど、CircleCIの設定ファイルに実行環境(利用するDockerイメージ)やcronの設定も含めることができるので、GitHubリポジトリでボットの自動実行環境もセットで配布できるのすっごい便利だ。。。

*1: 過去に実際、一時期自分のツイートだけがSearch APIで取れなくなる事象がありました https://twitter.com/sue445/status/897968605567926272

Pixela v0.2.0を出した

github.com

https://github.com/sue445/pixela/blob/master/CHANGELOG.md#v020

大きな変更点

Pixelaのエンドポイントをリソースっぽく扱うためのメソッドを作りました

~v0.1.1

# create graph
client.create_graph(graph_id: "test-graph", name: "graph-name", unit: "commit", type: "int", color: "shibafu")

# register value
require "date" 
client.create_pixel(graph_id: "test-graph", date: Date.today, quantity: 5) 

v0.2.0~

# create graph
client.graph("test-graph").create(name: "graph-name", unit: "commit", type: "int", color: "shibafu")

# register value
client.graph("test-graph").pixel(Date.today).create(quantity: 5)

経緯

sue445.hatenablog.com

先日作った時は最速(サービスリリース24時間以内?)で全APIを網羅したクライアントライブラリを出せたことに全く不満はなかったのですが、実際に使ってみるとPixelaのAPIを愚直にRubyのメソッドにマッピングしただけなので冗長な感は否めませんでした。

そこで、aws-sdk に対する aws-sdk-resources みたいな感じで使えるようにしました

何が嬉しいの?

上の例だけだといまいちメリットが分かりづらいですが、メソッドチェーンを分解して変数抽出することによりAPIをたくさん呼ぶ場合でもなるべく同じ引数を何回も書く手間を減らしてます

graph = client.graph("test-graph")

graph.create(name: "graph-name", unit: "commit", type: "int", color: "shibafu")
graph.pixel(Date.today).create(quantity: 5)

v0.1系までのメソッドとv0.2系以降のメソッドでどっちが使いやすいかはケースバイケースだと思うので、古い方のメソッドを消すつもりは今の所ありません。(実際APIのテストコードを書く時は前者の方が書きやすいので)

詳しい使い方はリファレンスを見てください。

https://www.rubydoc.info/gems/pixela/0.2.0/Pixela/Client

Itamae v1.9.12を出した

メンテナ業の報告です

リリースノート

https://github.com/itamae-kitchen/itamae/blob/master/CHANGELOG.md#v1912

v1.9.12の概要

PRを眺めてCIが通れば即マージできそうなPRに対して「遅くなってごめん。LGTMだけどCIがコケてるので最新のmasterを取り込んだらマージするよ(意訳)」ってコメントして、反応があったPRをマージしてリリースしました

リリースノートに書いてる変更内容

jail backend: add support of FreeBSD Jail (itamae jail)

github.com

FreeBSD Jailサポート

docker backend: Fixed edit action of file resource doesn't work with docker backend

github.com

ItamaeのCIを直す過程で見つけたバグの修正。(後述)

itamae docker でfile editできなかったのを修正

github.com

dry run実行時に (dry-run) がつくようになった

リリースノートに書いてない変更内容

WerckerからTravisCIに移行

github.com

  • CircleCIと違ってWerckerはワークフロー設定はymlだけで完結しない(メンテナが設定画面をいじる必要がある)ためPR送る側からすると不便
  • マトリクステストする場合はTravisCI使うのが圧倒的に楽
    • CircleCIでもできないことはないが記述量がTravisCIに比べて多くなる
  • DigitalOceanで立てたVMに対して itamae ssh するのがつらい
    • ssh越しだとCIが安定しない(ローカルのDockerコンテナに対してitamae実行する方がまだ安定する)
    • ssh越しのitamae実行なのでローカルに対してitamae実行するよりも確実にオーバーヘッドがある
    • VirtualBoxのtrusty(ローカル用)とDIgitalOceanのtrusty(CI用)は完全に同一じゃないので、ローカルとCIで挙動が違うのは罠
      • ローカル実行時にもDIgitalOcean使えばいい話なんだけど、アカウント登録して課金しないとVM立てられないのでハードルが高い
      • DockerイメージならローカルとCIで環境を完全に同一にできる
  • 最近の流行だとDockerでCIするのがモダン

みたいな思いを込めて英語でPRのdescriptionを書きました。

かつ、このCIを通すために既存のテストやバグも直しました。

控えめに言って今年一番頑張ったPRでした。

関連エントリ

blog.unasuke.com

マージ後にTravisCIを設定したり、PRをずっと放置してた関係で落ちてたテストを直してようやくmasterブランチのテストが全部通るようになりました。

gemspec更新

github.com

せっかくなので新メンテナの名前をgemspecに追加

今後もマージ後なるはやでリリースしていきたいと思うのでよろしくおねがいします