HTML等をGitHubへpushした時にWebサーバへ自動でデプロイする

HTMLなどの静的サイトをGitHubで管理していると,それを毎回手動でWebサーバへ反映させるのが面倒になってくる.

これを解決するために,GitHubとTravis CIを使って,GitHubのmasterブランチへpushした時に自動でWebサーバへデプロイする環境を作ったので,手順をまとめておく.

GitHubのリポジトリを準備

まずはHTML等を置いておくためのリポジトリをGitHubに作成しておく.

Travis CIとの連携

次に,Travis CIにGitHubのアカウントでログインする.

ログインしたら,右上のアカウント名の部分をから,「Accounts」へ移動する.すると,自分のGitHubリポジトリの一覧が表示される.
ここから,自動デプロイしたいリポジトリを探し出し,リポジトリ名の左側にある「×」をクリックして「◯」へ変更する.これでTravis CIとの連携設定が完了した.

サーバ側での設定

Webサーバ側で,自動デプロイ用に新しいユーザとグループを作成しておく.例ではCentOS7を使用している.

# useradd app
# passwd app
# groupadd deploy
# usermod -aG deploy app

ユーザとグループを作成し終えた後に,先程作成したユーザに切り替えてSSHのキーペアを作成する.この際, 作成するキーペアにパスフレーズを設定してはいけないことに注意する.ここでパスフレーズを設定してしまうと,Travis CIがWebサーバにデプロイしようとする際にパスフレーズ待ちで停止してしまうため,デプロイが完了しない.

# su - app
$ ssh-keygen
$ mv ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys

SSHキーペアの作成が完了したら,自動デプロイしたいリポジトリをサーバ側にcloneする.clone先はDocumentRootなど,実際に本番で配置する場所にする.

$ git clone <repository url> /path/to/document/root

リポジトリのclone後,Travis側からのpushを許可するために以下の設定を行う.

$ git config --local receive.denyCurrentBranch updateInstead

上記の設定まで完了したら,cloneしたリポジトリのディレクトリ内に移動し,SSH秘密鍵の暗号化を行う.暗号化にはTravis CLIを使用するため,必要に応じてインストールをしておく.

$ cd /path/to/repository
$ touch .travis.yml     # .travis.ymlを作成しておく
$ gem install travis -v 1.8.8 --no-rdoc --no-ri
$ travis login --org    # GitHubのアカウントでログイン
$ travis encrypt-file /path/to/private/key --add

秘密鍵の暗号化が完了すると, <秘密鍵の名前>.enc というファイルが生成されるので,存在を確認しておく.
暗号化した秘密鍵は,リポジトリ内に .travis ディレクトリを作成してその中に入れておくと良い.

$ mkdir .travis
$ mv id_rsa.enc .travis

ここまでの作業が終了したら,再度Travis CIの画面に戻る.先程GitHubリポジトリとTravis CIの連携を行った画面で,リポジトリ名の左にある歯車マークをクリックして設定画面へ移る.

設定画面へ移動したら,Environment Variablesの部分までスクロールし, encrypted_ から始まる環境変数が2つ設定されていることを確認する.もしこれらの変数が存在していない場合は,Travis CLIでログインが正しく出来ていないか,先程の秘密鍵暗号化の手順が上手くいっていない可能性があるので再度やり直す.

自動デプロイ用に次の3つの環境変数を追加する.追加の際,「Display value in build log」はOFFにしておく.これがONになっていると,ビルドログ中に設定した環境変数の値が表示されてしまう.

  • IP : デプロイ先WebサーバのIPアドレス
  • PORT : デプロイ先Webサーバへpushする際のポート.SSHを使う場合は22を指定する.
  • DEPLOY_DIR : Webサーバ内でのリポジトリ配置先を指定(例: /var/www/html ).

ここまで完了すればTravis CI側での設定は以上となる.

最後に, .travis.yml とデプロイ用に使用するシェルスクリプトを用意してリポジトリ内に配置する.
下記に .travis.yml と デプロイ用シェルスクリプト( deploy.sh )の例を掲載しておく.
.travis.yml 内の $encrypted_xxxxxx_key$encrypted_xxxxxx_iv に関しては,各自Travis CIのEnvironment Variablesに設定されていたものに変更する.

.travis.yml

addons:
    ssh_known_hosts: $IP

before_install:
- openssl aes-256-cbc -K $encrypted_xxxxxx_key -iv $encrypted_xxxxxx_iv
    -in .travis/id_rsa.enc -out .travis/id_rsa -d

script: ""

after_success:
    - ssh-keyscan -t rsa $IP >> ~/.ssh/known_hosts
    - bash .travis/deploy.sh

deploy.sh

#!/bin/bash

eval "$(ssh-agent -s)"
chmod 600 .travis/id_rsa
ssh-add .travis/id_rsa

git config --global push.default matching
git remote add deploy ssh://git@$IP:$PORT$DEPLOY_DIR
git push deploy master

.travis.yml はリポジトリの最上位階層, deploy.sh.travis ディレクトリ内に配置した.
最終的なディレクトリ構造は次のようになる.

.
├── index.html
├── .travis.yml
└── .travis
     ├── deploy.sh
     └── id_rsa.enc

ここまで完了したら,後はリポジトリにpushするたびに自動でTravis CIが動作し,サーバへ自動で変更を反映してくれるはず.

はてなブログからエクスポートした記事からはてなキーワードのリンクを削除する

はてなブログから他のブログへ移行する際,はてなブログから記事をエクスポートし,移行先のサービスへ記事をインポートするという作業をする.
しかし,はてなブログの無料版だと,はてなキーワードのリンクを削除することができない.

手作業で一つ一つ削除していくのは非常に面倒くさい.
そのため,一度データをエクスポートし,それを正規表現を使って編集することで対応した.

Vimでエクスポートしたファイルを開き,置換コマンドを使うと一発で完了する.

:%s/\v\<a>]+\>([^<]+)\<\/a\>/\1/g

これで完了.

はじめてのVimプラグインつくった

作成した経緯

私は普段から開発や文書作成にVimを愛用しているが,プレゼン用のスライドに関してはAppleのKeynoteを使って作成していた.

しかし,スライドもテキストベースでVimで作れると楽だなと思っていろいろ調べていた.
過去にはPandocを使ってMarkdownからスライド用PDFを生成する
ということも試したが,結局Keynoteに戻っていた.

いろいろ調べた結果,reveal.jsを使うとMarkdownで書いた文書をWebスライドとしてレンダリングできるということを知った.軽く使ってみた結果,使い勝手が良さそうだったので,これをVimからすぐに使えるようにプラグインとしてまとめた.

なお,今回が初のVimプラグイン開発なので,Vim Scriptの書き方がおかしいなどあるかもしれない.

プラグイン本体はGithubのmas9612/mdslide.vimにて公開している.

プラグインの内容

現在はまだ必要最低限の機能しか実装していない.現時点ではローカルWebサーバの起動・停止,Webスライドのオープン,スライド内容を強制的に更新する,という4つの機能のみを使うことができる.

reveal.jsの仕様上,発表者ノートなどの機能を使うためにはローカルサーバを動かす必要があるため,その機能を盛り込んである.

基本的にreveal.jsのMarkdown表記に従ってMarkdownを作成し,ローカルサーバを起動するだけでWebスライドがレンダリングされて見れるようになる.

これから・所感

まだ欲しい機能など実装できていない部分も多いので,少しずつ実装をすすめていく.
英語難しい.

tmux コピーモードでのキーバインド

tmuxの設定を読み込み直す際に次のようなエラーが出現.

invalid or unknown command: bind-key -t vi-copy v begin-selection
invalid or unknown command: bind-key -t vi-copy y copy-pipe "reattach-to-user-namespace pbcopy"

そういえば周りで同じエラーが出てる人を見たことがある気がするなあと思いながら調べると,
いつの間にか設定方法が変わっていたらしい.結構前からの変更だったようだが,
今までエラーが出なかったのはなぜかわからない.

というわけで,変更に合わせて次のように設定を書き換えた.

以前の設定

bind-key -t vi-copy v begin-selection
bind-key -t vi-copy y copy-pipe "reattach-to-user-namespace pbcopy"

新しい設定

bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "reattach-to-user-namespace pbcopy"

emacs-copyとvi-copyがそれぞれcopy-modeとcopy-mode-viに変更となったためにエラーが出ていたようです.

上記に限らず,emacs-copy,vi-copyに関しては次のように修正を加えれば良い.

  1. -t-T に変更する
  2. emacs-copyvi-copy は,それぞれ copy-modecopy-mode-vi に変更する
  3. コマンドの頭に send-keys -X をつける

これで今まで通りの操作をすることができるようになった.

SharePoint REST APIを使ってみた

SharePoint OnlineでサイトにアップロードしているExcelファイルを毎日自動でダウンロードしたいという要望をもらったので,
公開されているAPIを使ってやってみた.

環境

  • OS X El Capitan v10.11.6
  • Python 3.5.2
  • Office 365 Enterprise E3

Office 365 APIを使う

認証情報を取得する

Office 365 APIを使用するには,まずアクセストークンと呼ばれる認証情報を取得する必要がある.
次の手順でアクセストークンを取得する.

なお,今回はOffice 365 Enterprise E3を使用し,すでにSharePointでサイトを作成していることとする.

  1. 新Azure PortalにOffice 365の管理者アカウントでログインする.
  2. 左側のメニューから「Azure Active Direcotory」を選択する.
  3. メニューから「アプリの登録」を選択する.
  4. ページ上部にある「追加」を選択して新規アプリケーションを作成する.
    • 名前: 好きなものを
    • アプリケーションの種類: Webアプリ/API
    • サインオンURL: 作成したアプリケーションを動かすURL
  5. アプリケーションの作成後,作成したアプリケーションを選択して,以下の情報をメモしておく.
    • アプリケーションID
    • ホームページ(サインオンURLで指定したものになっているはず)
  6. 右側の設定メニューから「キー」を選択して新しくキーを作成する.
    キーの説明を入力して期間をドロップダウンリストから選択し,保存をクリックするとキーが生成される.
    この時キーを 必ず メモしておくこと(この画面から移動した後はキーを再確認できない).
  7. 設定メニューから「必要なアクセス許可」を選択してアプリケーションに対して必要な権限を付与する.
    今回は,SharePointの機能を使いたいので,上部にある「追加」をクリック後,表示されるサービス名の中から
    「Office 365 SharePoint Online」を選択し,必要な権限を追加する.
  8. アクセストークンを生成するために必要な code を取得する.次のURLにGETでリクエストを送信する.
    • URL: https://login.windows.net/common/oauth2/authorize?response_type=code&client_id=<client_id>&resource=<resource>&redirect_uri=<redirect_uri>
    • パラメータ
      • client_id : アプリケーションID
      • resource : https://<テナント名>.sharepoint.com/
        (例: テナント名が testtenanthttps://testtenant.sharepoint.com/
      • redirect_uri : サインオンURL
  9. 正しくリクエストを送れていればログイン画面が表示され,ログインが成功すると redirect_uri で指定したURIにリダイレクトされ,パラメータに code がセットされる.
  10. 取得した code を用いてアクセストークンを取得する.次のURLにPOSTでリクエストを送信する.
    • URL: https://login.windows.net/common/oauth2/token
    • HTTPヘッダに追加: Content-Type: application/x-www-form-urlencoded
    • リクエストボディ: grant_type=authorization_code&code=<code>&client_id=<client_id>&client_secret=<client_secret>&redirect_uri=<redirect_uri>
    • パラメータ
      • code : 先程取得したもの
      • client_secret : アプリケーション作成時に生成したキー
  11. 正しくリクエストを送れていれば, access_token を含むJSONが返却される.

APIを叩く

上記の手順で取得したアクセストークンを使用して実際にAPIを使用した.
APIを叩くときには,HTTPヘッダに取得したアクセストークンを以下のようなフォーマットで加える必要がある.

Authorization: Bearer <access_token>

今回はSharePointのサイト上にアップロードしているExcelファイルをダウンロードするのが目的なので,
それっぽいAPIをリファレンスから探し出して叩いてみた.

SharePoint 2013 REST API リファレンスによれば,
Fileというリソースがサイト内のファイルを表していて,そのファイルを取得するには次のようなURIを指定すれば良い.

http://<site_url>/_api/web/getfilebyserverrelativeurl('/<folder>/<file>')

また,ファイル自体をダウンロードするためには, $value というODataのクエリオプションを付加する.

というわけで,Pythonで簡単にAPIを叩く.なお,以下のプログラムではRequestsという外部ライブラリを使用しているので注意.

import requests
import urllib.parse

def main():
    # ファイル自体を取得するため,$valueを付加
    uri = "https://<tenant>.sharepoint.com/_api/web/getfilebyserverrelativeurl('<file-path>')/$value"
    access_token = sys.argv[1]
    headers = {
        'accept': 'application/json;odata=verbose',
        'Content-Type': 'application/json;odata=verbose',
        'Authorization': 'Bearer ' + access_token,
    }
    res = requests.get(urllib.parse.quote(uri, safe=':/'), headers=headers, stream=True)
    with open('file.xlsx', 'wb') as f:
        f.write(res.raw.read())


if __name__ == '__main__':
    main()

これを実行すると,URIに指定したファイルが file.xlsx という名前でダウンロードされる.

まだ未完成なところ

  • 現時点では code を取得する際にブラウザを使う必要がある
    • Requestsモジュールの Session を使えばできるようなので後で修正する

参考にしたところ