KAROUSHI -Japanese Engineer Blog-

コボルドからドラゴンへ -Kobold to Dragon-

システムエンジニアのブログです。サイト名は「雑魚キャラからボスキャラへレベルアップしたい!」という思いを込めて命名しました。自分はやっとリザードマンになったくらいです。

WindowsでHexo+GitHub Pagesでデプロイまで実行できなかった話

ブログ向けの静的ジェネレータを探していたらHexoがよさそうだったのでまずはインストールして使ってみることにしました。
Hexoはnode.js製なのでnpmが必要なのでそこからのWindows版インストール手順をまとめてみました。
が、結論から言うとHexoでサイト作成はうまくいきましたが、GitHub Pagesへデプロイはできませんでした。
Windows環境でうまく言った方アドバイスをいただけると助かります。

目次

構築環境

OS: Windows10
node: v8.11.3

node.jsのダウンロードとインストール

node.jsの公式サイトからWindows64bit版のnode.jsをダウンロードしてください。
https://nodejs.org/ja/

ダウンロードしたexeをクリックしてインストールをします。インストールが完了したらコマンドプロンプトを起動して以下コマンドを実行してください。

> node -v
v8.11.3

>npm -v
5.6.0

hexoをインストール

npmでhexoをインストールします。

> npm install -g hexo

途中で以下のようなWarnが出ますが特に問題ない模様。

npm WARN deprecated titlecase@1.1.2: no longer maintained
・・・省略・・・
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\hexo\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

インストールが完了したら以下コマンドを実行してください。

> hexo -v
hexo-cli: 1.1.0
os: Windows_NT 10.0.17134 win32 x64
http_parser: 2.8.0
node: 8.11.3
v8: 6.2.414.54
uv: 1.19.1
zlib: 1.2.11
ares: 1.10.1-DEV
modules: 57
nghttp2: 1.32.0
napi: 3
openssl: 1.0.2o
icu: 60.1
unicode: 10.0
cldr: 32.0
tz: 2017c

サンプルブログを作ってみる

以下コマンドを実行してmyblogというブログのひな型を作成します。
ちなみに実行したディレクトリにmyblogディレクトリを作成するので、実行前に任意の場所にcdで移動しておいてください。

>hexo init myblog
INFO Cloning hexo-starter to ~\Desktop\サイト\hexo\myblog
Cloning into 'myblog'...
remote: Counting objects: 65, done.
remote: Total 65 (delta 0), reused 0 (delta 0), pack-reused 65
Unpacking objects: 100% (65/65), done.
Checking connectivity... done.
Submodule 'themes/landscape' (https://github.com/hexojs/hexo-theme-landscape.git) registered for path 'themes/landscape'
Cloning into '/myblog/themes/landscape'...
Submodule path 'themes/landscape': checked out '73a23c51f8487cfcd7c6deec96ccc7543960d350'
[32mINFO [39m Install dependencies
npm WARN deprecated titlecase@1.1.2: no longer maintained

> nunjucks@3.1.3 postinstall myblog\node_modules\nunjucks
> node postinstall-build.js src

npm WARN rollback Rolling back node-pre-gyp@0.10.0 failed (this is probably harmless): EPERM: operation not permitted, scandir 'myblog\node_modules\fsevents\node_modules'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

added 400 packages in 18.869s
INFO Start blogging with Hexo!

すると以下のような構成のディレクトリが作成されます。
myblog
├node_modules
├scaffolds
├source
├themes
├.gitgnore
├_config.yml
├package.json
└package-lock.json

サーバを起動する。
>hexo server
INFO Start processing
INFO Hexo is running at http://localhost:4000/. Press Ctrl+C to stop.

ブラウザを開いて以下にアクセスをしてみてください。
http://localhost:4000/

このような画面が表示されればOKです。

Github pagesの設定

Githubにログインし、タブメニュの[Settings]を開き"GitHub Pages"の以下を設定して[Save]を押す。
Source: master branch

すると"Your site is ready to be published at "の後ろに公開されるページのURLが記載されているのでコピーしておきます。

パッケージのインストール

Hexoはバージョン3からデプロイ機能が本体から切り離されたので以下パッケージをインストールします。

npm install hexo-deployer-git --save

configにgithubを設定

hexoの_config.ymlを以下のように編集します。
repoは自分のGitリポジトリによって適宜修正すること。

# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://yoursite.com
root: /
permalink: :year/:month/:day/:title/
permalink_defaults:

・・・省略・・・

# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
  type: 

↓

# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: https://【アカウント名】.github.io/【リポジトリ名】/
root: 【リポジトリ名】
permalink: :year/:month/:day/:title/
permalink_defaults:

・・・省略・・・

# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
  type: github
  repo: 【Git リポジトリURL】
  branch: master

github pagesにdeploy

コマンドプロンプトを開いて、myblogのディレクトリまで移動し以下コマンドを実行してdeployします。

hexo deploy -g

※ココでエラーになる。

トラブルシューティング

deployコマンド実行時に/dev/ttyにデバイスとアドレスが見つからない

【手順】
以下をコマンドを実行する
>hexo deploy -g

【ログ】
標準出力で以下が表示される。
Fatal: HttpRequestException encountered.
bash: /dev/tty: No such device or address
error: failed to execute prompt script (exit code 1)
fatal: could not read Username for 'https://github.com': Invalid argument
FATAL Something's wrong. Maybe you can find the solution here: http://hexo.io/docs/troubleshooting.html
Error: Fatal: HttpRequestException encountered.
bash: /dev/tty: No such device or address
error: failed to execute prompt script (exit code 1)
fatal: could not read Username for 'https://github.com': Invalid argument

at ChildProcess. (myblog\node_modules\hexo-util\lib\spawn.js:37:17)
at emitTwo (events.js:126:13)
at ChildProcess.emit (events.js:214:7)
at ChildProcess.cp.emit (hexo\myblog\node_modules\cross-spawn\lib\enoent.js:40:29)
at maybeClose (internal/child_process.js:925:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:209:5)

【原因】
Windows環境のため/dev/ttyなんてディレクトリは存在しない。

【対処方法】
repoに"http"ではなく"ssh"接続のURLを設定したが解消されず。

ホストキーの認証に失敗

【手順】
以下をコマンドを実行する
>hexo deploy -g

【ログ】
標準出力で以下が表示される。
nothing to commit, working directory clean
Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
FATAL Something's wrong. Maybe you can find the solution here: http://hexo.io/docs/troubleshooting.html
Error: Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

at ChildProcess. (myblog\node_modules\hexo-util\lib\spawn.js:37:17)
at emitTwo (events.js:126:13)
at ChildProcess.emit (events.js:214:7)
at ChildProcess.cp.emit (myblog\node_modules\cross-spawn\lib\enoent.js:40:29)
at maybeClose (internal/child_process.js:925:16)
at Socket.stream.socket.on (internal/child_process.js:346:11)
at emitOne (events.js:116:13)
at Socket.emit (events.js:211:7)
at Pipe._handle.close [as _onclose] (net.js:557:12)

【原因】
Gitに登録されている秘密鍵の設定がおかしいため認証に失敗している。

【対処方法】
不明。
Git Bashの場合、Windowsユーザの配下にある.sshディレクトリに公開鍵と秘密鍵を設定してみましたが、改善されず。

Netbeans+PHPUnit+Mockeryで単体テスト環境を構築

NetbeansPHPUnit+Mockeryを入れて単体テストを動作させる記事がなかったのでメモ程度で作成。

目次

事前環境

  • Netbeansを入れておく
  • Xampp(PHP 7)を入れておく
  • composerを入れておく

composerでPHPUnit+Mockeryをインストール

適当なプロジェクトで右クリック→[composer]→[初期化]を実行すると、composer.jsonが作成される。
その後、プロジェクトで右クリック→[composer]→[依存性の追加]を押すと、パッケージのウィンドウが表示される。
トークン」欄に"phpunit"と入力してEnterを押すとパッケージ検索が開始されます。
しばらく待つと検索結果に"phpunit/phpunit"が出てくるので選択すると、今度はバージョン検索が走ります。
使用可能なバージョンから"7.1.5"を選択し[必須(dev)]を押してインストールを開始してください。
同様の手順で"mockery/mockery"の"1.1.0"をインストールします。

netbeansphpunitの設定

プロジェクトを右クリック→[構成を設定]→[カスタマイズ]を選択します。
プロジェクトプロパティ画面が開き、左メニュの[テスト]を選択し[フォルダの追加]を押し、新規フォルダ"tests"を作成して[開く]で追加します。
同画面の下部にある"テスト・プロバイダ"より"PHPUnit"を選択して[OK]を押します。

サンプルソース単体テストを用意する。

TemperatureとTemperatureTestを作成します。
TemperatureTestはテストフォルダに作成してください。
ちなみに本ソースは以下公式サイトを日本語化したサイトのものを引用しています。
Mockery 0.8.0 日本語ドキュメント

Temperatureのソース

<?php
class Temperature
{ 
    public function __construct($service)
    {
        $this->_service = $service;
    }
 
    public function average()
    {
        $total = 0;
        for ($i=0;$i<3;$i++) {
            $total += $this->_service->readTemp();
        }
        return $total/3;
    }
}

TemperatureTestのソース

<?php
require_once "../Temperature.php";
require __DIR__ . '/../vendor/autoload.php';
use \Mockery as m;

class TemperatureTest extends PHPUnit_Framework_TestCase
{
    public function tearDown()
    {
        m::close();
    }
 
    public function testAverage()
    {
        $service = m::mock('service');
        $service->shouldReceive('readTemp')->times(3)->andReturn(10, 12, 14);
        $temperature = new Temperature($service);
        $this->assertEquals(12, $temperature->average());
    } 
}

今回少しハマったのがrequireの部分。公式サイトではこの2行がなくてコピーしただけでは"PHP fatal error"が出力され動きませんでした。
公式サイトを読み進めていくと、実は以下に書いてあります。

Composerをご利用でしたら、Composerが生成したオートローダーファイルをシンプルにincludeするだけですみます。
require __DIR__ . '/../vendor/autoload.php'; // vendorディレクトリがひとつ上の階層であると仮定

初めて動かすときはコピペでやる人が多いと思うのでサンプルソースにはrequireも書いてほしいですね。
↑のrequireとテスト対象のソースをrequireすれば単体テスト動きました。

Windows10にRubyをインストールする手順

Javaが有償化するので他の言語を学ぼうと思いたり、PythonRuby、Goどれがいいかなと調べてみたらRuby on Railsというフレームワークが便利そうなのでひとまずRubyをインストールしてみました。(Ruby on Railsはまた別途)
というわけで今日はRubyをWindows10にインストールしてみます。

環境

OS:Windows10
RubyRuby+Devkit 2.5.1-1 (x64)

Rubyをインストール

まずは以下からRuby+Devkit 2.5.1-1 (x64) をダウンロードします。
https://rubyinstaller.org/downloads/
f:id:jainders:20180521014342j:plain

"I accept the Licence"を選択して"Next"を押します。
f:id:jainders:20180521014345j:plain

"Use UTF-8 as default external encording."にチェックを入れて"Install"を押します。
他はそのままでOKです。
f:id:jainders:20180521014348j:plain

そのまま"Next"を押します。
f:id:jainders:20180521014351j:plain

インストール中です。完了するまで待ちます。
f:id:jainders:20180521014354j:plain

そのまま"Finish"を押します。
f:id:jainders:20180521014357j:plain

以下のような画面が立ち上がるのでそのままEnterキーを押して続行します。
f:id:jainders:20180521014401j:plain

そのままEnterキーを押して終了します。
f:id:jainders:20180521014404j:plain

Windowsの検索から"Intaractive Ruby"を起動すると以下のような画面が立ち上がります。
f:id:jainders:20180521014407j:plain

またコマンドプロンプトで実行するためにはWindows環境変数を編集を起動して、ユーザ環境変数の”Path”にRubyがインストールされたディレクトリを設定します。(今回は”C:\Ruby25-x64\bin”)
その後、コマンドプロンプトを起動して"ruby -v"を実行して動作確認してみましょう。
バージョンが表示されれば問題ありません。
f:id:jainders:20180522012753j:plain

以上でRubyのインストールは完了です。

WindowsにOpenJDKをインストールする手順

2018年9月のJava11からOracleJDKが有償化され、今後は有償プランか、OpenJDKへ移行になると思います。
個人利用する方はOpenJDK一択になるため、今回Windowsのインストールを試してみました。

OpenJDK(RedHat)のダウンロード

以下RedHatからOpenJDK(Windows Installer)をダウロードしてください。
OpenJDK Download | Red Hat Developers

ダウンロードのためにはRedHatアカウントが必要です。
f:id:jainders:20180415192957p:plain

OpenJDK(RedHat)のインストール

OpenJDKのインストールはJavaFXが必要な場合、インストール時にチェックしてください。
あとは環境変数のPathにOpenJDKのjava.exeが存在するディレクトリを指定すれば動きます。
ただし、OracleJDK8以降が事前にインストールされていた場合、環境変数JAVA_HOMEやPathを設定するだけではないので口述します。

環境変数の設定

Windows検索欄に"システムの詳細設定の表示"と入力→「環境変数」を押す。

OracleJDK8以前と以降で参照する環境変数が異なります。
OracleJDK8以前:JAVA_HOMEにパスを設定
OracleJDK8以降:システム環境変数の"Path"の"C:\ProgramData\Oracle\Java\javapath"

それぞれ以下のように対策します。
OracleJDK8以前:JAVA_HOMEのパスを変更
OracleJDK8以降:システム環境変数の"Path"の"C:\ProgramData\Oracle\Java\javapath"の優先度を下げ、それより上にOpenJDKのディレクトリを設定する。

右側の「下へ」を押して"C:\ProgramData\Oracle\Java\javapath"の優先度を下げてください。
またOpenJDKのディレクトリを直接入力せず、「%JAVA_HOME%\bin」を入れてJAVA_HOMEにJDKディレクトリを入れると、今までと同様に運用できる。
f:id:jainders:20180415212510p:plain

Grailsで起動時のポート番号を変更

Grailsでrun-appを実行するとデフォルトではポート番号:8080で起動します。
このポート番号を変更する方法がいくつかあったので整理してみました。

grails> run-app
・・・中略・・・
Grails application running at http://localhost:9090 in environment: development

目次

■application.ymlに記述
application.ymlの冒頭に以下を追加する。

---
server:
    port: 9090

■起動コマンド実行時にオプションで指定
起動コマンド実行時にportオプションで番号を指定する。

>grails run-app -port 8090

環境変数で指定
環境変数GRAILS_OPTSに"-Dserver.port"に指定する。

Windows10のpowershellを使ってる場合、set-itemで環境変数に設定できる。

>set-item env:GRAILS_OPTS -value "-Dserver.port=8100"
>get-item env:GRAILS_OPTS

Name                           Value
----                           -----
GRAILS_OPTS                    -Dserver.port=8100

IntelliJ IDEAでPlantUMLプラグインをインストールしてリアルタイムにUMLをプレビュー表示する

UMLツールの代表だったastahが有料になってしまったため代替を探していたら、PlantUMLという無料UMLツールを見つけたので紹介します。
PlantUMLを使うことによって以下のようなメリットがあります。
メリット:

  1. テキストで保存できるためGitやSVNリポジトリ管理できるので差分確認が可能
  2. 図の見栄えの統一
  3. シーケンス図やクラス図への追加削除が容易
  4. 無償

目次

PlantUMLプラグインのインストール

IntelliJ IDEAを起動してメニュより「File」→「Settings」→「Plugins」の画面の下部にある「Browse repositories...」を押下します。そこで開いた画面上部の検索ボックスに"PlantUML"と入力すると、"PlantUML integration"というプラグインが出てくるので「install」を押してインストールしましょう。
インストールが完了したら、IntelliJ IDEAを再起動して有効化します。
f:id:jainders:20180216153840p:plain
f:id:jainders:20180216153846p:plain

Graphvizをダウンロード

図の表示にはGraphvizを使用します。以下からサイトにアクセスしてstable版(msiまたはzip)をダウンロードしてきます。
http://www.graphviz.org/download/
ダウンロードしたら解凍して"C:\Program Files (x86)\graphviz-2.38\"のように配置します。
f:id:jainders:20180216154117p:plain

IntelliJ IDEAでGraphvizの設定

メニュより「File」→「Settings」→「Other Settings」を選択すると画面に"PlantUML"のリンクがあるのでクリックします。
Graphviz dot executable」の入力欄に先ほど配置したgraphviz配下にあるdot.exeのパスを入力します。
例:C:\Program Files (x86)\graphviz-2.38\release\bin\dot.exe
f:id:jainders:20180216154452p:plain

UMLの作成

適当なプロジェクト上で右クリックして「UML xxxx」を選択して作成します。今回はUML Classでファイル名はSampleClassで決定にします。
f:id:jainders:20180216154504p:plain
するとSample.pumlというファイルが作成され、デフォルトで以下が記述されており、右側に図が表示されます。

@startuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

Alice -> Bob: Another authentication Request
Alice <-- Bob: another authentication Response
@enduml

f:id:jainders:20180216154627j:plain

CodeceptionのRESTでsetCookieを実行したい

CodeceptionのRESTでsetCookieをしようとするとsetCookieがないというエラーがでる。こんな感じ。

  [RuntimeException] Call to undefined method ApiTester::setCookie  

よくよく公式サイトを調べてみると、確かにRESTはsetCookieメソッドが存在しない。
REST - Codeception - Documentation

でもRESTでCookieを設定するテストがあるため、どうにかできないか悩んでアレコレやっていたらHelperに自作メソッドを作るしかない!という感じになりました。
が、、、、これも日本語のサイトでドンピシャな内容が全然ないため、すっごい悩んでたら今さっきやっと解決したので載せておきます。

目次

RESTでsetCookieを呼び出す方法

前提

プロジェクト名: api

yamlにHelperを記述

yamlファイルに以下のようににHelperを記述する。(プロジェクト生成時にデフォルトで記載されている)
このHeplerにsetCookieメソッドを作成する。

$ vim tests/api.suite.yml
actor: ApiTester
modules:
    enabled:
        - REST:
            url: http://localhost/
            depends: PhpBrowser
            part: Json
        - \Helper\Api

setCookieメソッドを作成

setCookieメソッドも1から作る必要はありません。getModule()を使えば他モジュールのメソッドを呼び出すことができるようになります。あとはPhpBrowserのものを同じメソッド名でラッパーするだけです。

$ vim tests/support/Helper/Api.php
<?php
namespace Helper;

// here you can define custom actions
// all public methods declared in helper class will be available in $I

class Api extends \Codeception\Module
{
  function setCookie($name, $value) {
    $this->getModule('PhpBrowser')->setCookie($name, $value);
  }
}

クッキーをセットしてGET送信

今回実行する受け入れテストは以下のようなもの。

$ vim tests/api/SampleTestCept.php
<?php
$I = new ApiTester($scenario);
$I->wantTo('perform actions and see result');
$I->setCookie('sessionid', 'el4ukv0kqbvoirg7nkp4dncpk3');
$I->sendGET('/');
$I->seeResponseCodeIs(200);

debugモードで実行してリクエストの中身を確認してみます。

$ php codecept run api --debug
・・・中略・・・
SampleTestCept: Perform actions and see result
Signature: SampleTestCept
Test: tests/api/SampleTestCept.php
Scenario --
 I set cookie "sessionid","el4ukv0kqbvoirg7nkp4dncpk3"
  [Cookie Jar] ["sessionid=el4ukv0kqbvoirg7nkp4dncpk3; path=/; httponly"]
 I send get "/"
・・・中略・・・

念のためnginxのログも事前にログフォーマットで"sessionid"のCookieを表示するように設定しておき、ちゃんと受信できているか確認してみます。
nginxのコンフィグ設定はこんな感じ。

$ sudo vim /etc/nginx/nginx.conf
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$cookie_sessionid"';

    access_log  /var/log/nginx/access.log  main;

ログを確認結果。

$ sudo tail /var/log/nginx/access.log 
127.0.0.1 - - [14/Feb/2018:16:37:44 +0000] "GET // HTTP/1.1" 200 3770 "-" "Symfony BrowserKit" "-" "el4ukv0kqbvoirg7nkp4dncpk3"