Hiki on VPS から Gollum on heroku sync with BitBucket へ移行した話


ずっと使ってるHikiがあるけど、いい加減、Hiki記法を忘れてるので、Markdownなwikiに移行することにした。Markdownだとdlの対応がないから本当はAsciiDocのほうがいいんだけど、マイナーなマークアップに移るんならHikiのままでいいやとなったので、GollumとGithub Flavored Markdownを選択。

## tl;dr

[shrkw/gollum-auto-backup](https://github.com/shrkw/gollum-auto-backup)にもろもろソースコードを置いたので動かすのに何が必要かわかるはず。

## やったこと

- [x] Localで動かす
 - [x] 普通に動く
 - [x] Basic認証かける
 - [x] Hookでgit pushする
 - [x] BitBucketにpushする
- [x] Github Flavored Markdownを使う
- [x] Herokuで動かす
 - [x] git pushもちゃんと動くこと
- [x] hikiのデータをmarkdownにコンバート

## Localで動かす

準備

```
$ mkdir Desktop/shr-gollum
$ cat Gemfile
source 'https://rubygems.org'
ruby '2.2.2'
gem 'gollum', '~> 4.0.1'
gem 'github-markdown', '~> 0.6.9'
$ bundle install --path=vendor/bundle
```

起動

```
$ cd /tmp
$ git clone git@github.com:shrkw/gollumwiki.git
$ bundle exec gollum /tmp/gollumwiki
```

確認

```
$ cd /tmp/gollumwiki/
$ git log
commit f201b8be8803d0fc29f78b2308825baa6ef6710c
Author: shrkw <shrkwh@gmail.com>
Date:   Thu Dec 24 23:21:14 2015 +0900

    Created foo (markdown)

commit 4e10983baad0c3c6183aa6972c9b64f102008fbd
Author: shrkw <shrkwh@gmail.com>
Date:   Thu Dec 24 23:21:02 2015 +0900

    Created Home (markdown)
```

### Basic認証かける

[gollum-on-heroku/precious.rb at master · naoa/gollum-on-heroku](https://github.com/naoa/gollum-on-heroku/blob/master/precious.rb)をパクって認証かける。

```ruby
#!/usr/bin/env ruby
require 'rubygems'
require 'gollum/app'

module Precious
  class App < Sinatra::Base
    basic_auth_username = ENV['BASIC_AUTH_USERNAME']
    basic_auth_password = ENV['BASIC_AUTH_PASSWORD']
    if basic_auth_username && basic_auth_password
      before do
        authorize
      end
    end

    private
    def authorize
      response['WWW-Authenticate'] = %(Basic realm="Restricted area.")
      throw(:halt, [401, "Not authorized\n"]) unless authorized?
    end

    def authorized?
      basic_auth_username = ENV['BASIC_AUTH_USERNAME']
      basic_auth_password = ENV['BASIC_AUTH_PASSWORD']

      @auth ||=  Rack::Auth::Basic::Request.new(request.env)
      @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == [basic_auth_username, basic_auth_password]
    end
  end
end
```

### Hookでgit pushする

[naoa/gollum-on-heroku](https://github.com/naoa/gollum-on-heroku) がすごく参考になった。
Hookが使えるとか、[gollum/gollum-lib](https://github.com/gollum/gollum-lib)にしか書いてないのに使っててすごい。

```
wiki = Gollum::Wiki.new(gollum_path)
Gollum::Hook.register(:post_commit, :hook_id) do |committer, sha1|
#  wiki.repo.git.pull("origin", "master")
  wiki.repo.git.push("origin", "master")
end
```

### BitBucketにpushする

すごいめんどくさい。なぜならBitBucketのOAuth Access Tokenは1時間で失効してしまうから [[OAuth on Bitbucket Cloud - Atlassian Documentation](https://confluence.atlassian.com/bitbucket/oauth-on-bitbucket-cloud-238027431.html#OAuthonBitbucketCloud-Refreshtokens)]。
なので、こんなプロセスが毎時で必要になる。

1. refresh_tokenのAPI叩いて新しいAccess Tokenを取得
 - `curl -X POST -u "client_id:secret" https://bitbucket.org/site/oauth2/access_token -d grant_type=refresh_token -d refresh_token={refresh_token}`
2. configのurlを更新
 - `git remote set-url origin https://x-token-auth:{access_token}@bitbucket.org/shrkwh/gollumwiki.git`

~~もしくは、これ用のsshキーを登録しておいて、sshプライベートキーを環境変数に渡して、dyno起動のたびにファイルに出力する、とか。それもイヤだけど。~~

non-expiringなAPI tokenも検討してはいるらしい [[comment from Atlassian guy](http://stackoverflow.com/questions/24965307/how-to-manipulate-bitbucket-repository-with-token/31398521#comment53581278_31398521)]。一応、Bitbucketのissue trackerにも追加しておいた [[site / master / issues / #12186 - non-expiring auth access tokens (BB-15425) — Bitbucket](https://bitbucket.org/site/master/issues/12186/non-expiring-auth-access-tokens)]。

### もしくは、dynoの起動時にアクセストークン取得する

1. OAuth2キーとシークレットを環境変数で登録
2. dyno起動時にアクセストークン取得
3. それを使ってBitBucketからclone
4. dyno起動中はそれでpushする

dynoは毎日rebootしてるみたいだし、これでいいか。なんかうまくいかなかったらまた考えよう。

```ruby
require 'net/http'
require 'uri'
require 'openssl'
require 'json'
require 'logger'

def fetch_access_token(key, secret)
  logger = Logger.new(STDERR)
  url = URI.parse('https://bitbucket.org/site/oauth2/access_token')
  req = Net::HTTP::Post.new(url.path)

  req.basic_auth key, secret
  req.set_form_data({'grant_type'=>'client_credentials'}, ';')
  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  #http.set_debug_output $stderr
  res = http.start {|http| http.request(req) }
  case res
  when Net::HTTPSuccess, Net::HTTPRedirection
    logger.info('Fetching Access Token Succeed')
    js = JSON.parse(res.body)
    js['access_token']
  else
    raise StandardError, 'Fetching Access Token Failed'
  end
end
```
[gollum-auto-backup/bitbucket.rb at master · shrkw/gollum-auto-backup](https://github.com/shrkw/gollum-auto-backup/blob/master/bitbucket.rb)

## Github Flavored Markdownを使う

もともと`github-markdown`に対応してた [[gollum/README.md at master · gollum/gollum](https://github.com/gollum/gollum/blob/master/README.md)]。`Gemfile`に書けばOK。

```
gem 'github-markdown'
```

## Herokuで動かす

`buildpack-multi`使うと`.buildpacks`ファイルで複数のbuildpackが指定できるようになるのね。で、Heorku Deployボタんからの起動ならapp.jsonに指定できるけど、コマンドからなら、以下で指定。

```
heroku buildpacks:set https://github.com/heroku/heroku-buildpack-multi.git
```

その他のconfigも適宜指定。

```
heroku config:add GIT_REPO_PATH="shrkw/gollumwiki"
heroku config:add OAUTH_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

### git pushもちゃんと動くこと

`https://x-token-auth:{access_token}@bitbucket.org/shrkwh/gollumwiki.git`でcloneできてれば、上記のhookでちゃんとpushできる。

## HikiのデータをMarkdownにコンバート

[masasuzu/p5-App-hiki2md](https://github.com/masasuzu/p5-App-hiki2md)があったので使う。と思ったら微妙に空白の対応が期待してたのと違う。ので、folk [[shrkw/p5-App-hiki2md](https://github.com/shrkw/p5-App-hiki2md)]　して、ついでにテーブルにざっくり対応させた。

perlの書き方とか動かし方全くもって忘れてた。

```
export PERL5LIB=/Users/shrkw/.ghq/github.com/shrkw/p5-App-hiki2md/lib
perl ./bin/hiki2md Src > Dest
```

できたファイルをgitのリポジトリにコミットしてpushして終わり。

## まとめ

というわけでBitBucketとsyncするgollumがHerokuに建てられました。サクッと終わると思ってたけど毎日少しずつ進めてたら冬休み中かかってしまった。

Markdownでtodoリスト作って進めると、進捗がわかりやすくて助かった。

## 参考

- [Deploy to HerokuボタンでGitベースのWiki gollumを無料で簡単に作れるようにした - CreateField Blog](http://blog.createfield.com/entry/2015/09/21/214232)


- [githubのwikiエンジン"gollum"の導入と細かい設定 - yukke::note](http://yukke.hateblo.jp/entry/2013/05/02/224859)
- [hfm/wiki](https://github.com/hfm/wiki)
- [Gollum on Heroku](http://www.javiersaldana.com/tech/2014/02/07/gollum-on-heroku.html)
- [gollumを使って個人用wikiをサーバに立てた | blog: takahiro okumura](http://blog.hifumi.info/2014/02/02/my-wiki-powered-by-gollum/)
- [Github製wikiエンジン&quot;Gollum&quot;インストール - Qiita](http://qiita.com/urunru@github/items/d4708bca0b70009856ec)