Excelファイルの更新をJenkinsに監視させる

サーバに置かれたExcelファイルの更新を定期的に確認するという心躍る楽しい作業が有る。たまにファイルを見に行って、ファイルが更新されているか否か確認するだけの単純作業とは言え、せっかく確認しても更新されているとは限らないし、第一、桜が花開く春の季節にそんな退屈な仕事をするようでは心が寒くなってしまう。そこでJenkinsにファイル監視を代行させることにした。

前提条件

  • Windows上でJenkinsを稼働させている
  • サーバに置かれたExcelファイルはJenkinsからアクセス可能である(アクセス可能な権限でJenkinsが動作している)

ファイル更新の監視

Jenkinsのジョブのトリガーには、ファイル監視を行うFSTriggerプラグインを利用した。単純に更新のタイミングさえ分かれば良いのなら、これだけで良い。

FSTrigger provides polling mechanisms to monitor a file system and trigger a build if a file or a set of files have changed.

FSTrigger Plugin - Jenkins - Jenkins Wiki

最終更新者の取得

せっかくなのでExcelファイルのプロパティも知らせて欲しい。そんな情報はxdoc2txtで取得可能だ。

xdoc2txtはPDF,WORD,EXCEL,一太郎などの各種バイナリ文書から、テキスト要素を抽出する汎用テキストコンバータであり、Windowsコマンドラインで動作します。

xdoc2txt

こんなバッチファイルを用意しておき、Jenkinsのジョブで呼び出す。この時、"-p"オプションを使うとExcelファイルのプロパティが出力される。

chcp 65001
set XDOC2TXT="C:\Program Files\xd2tx200\command\xdoc2txt.exe"
set SRC_FILE="\\path\to\file.xlsx"

echo __START_OF_LOG__
%XDOC2TXT% -p -8 %SRC_FILE%
echo __END_OF_LOG__

メール送信処理にはEmail-ext pluginを利用した。

This plugin allows you to configure every aspect of email notifications. You can customize when an email is sent, who should receive it, and what the email says.

https://wiki.jenkins-ci.org/display/JENKINS/Email-ext+plugin

メール本文として「ログの中でデリミタで指定された範囲」を選択出来るので、上記で使ったデリミタを指定する。

${BUILD_LOG_EXCERPT, start="__START_OF_LOG__", end="__END_OF_LOG__"}

結果的に、こんな内容のメールが届くことになる。Excelファイルの最終更新者や更新日時が分かるのは便利だ。(もちろん、短時間に何人も更新したら途中の更新履歴までは分からないけど、そこは無視する)

<Author>foo</Author>
<LastAuthor>rabbit2go</LastAuthor>
<ApplicationName>Microsoft Excel</ApplicationName>
<EditTime>2015/03/31 20:08:42</EditTime>
<LastPrinted>2015/03/18 10:35:03</LastPrinted>
<Created>2014/10/11 18:08:32</Created>

変更箇所の差分取得

せっかくxdoc2txtを使うのだから、テキスト化した情報を元に「ファイル更新内容」を通知してみる。具体的には下記のようなバッチファイルを呼び出せば良い。

chcp 65001
set XDOC2TXT="C:\Program Files\xd2tx200\command\xdoc2txt.exe"
set SRC_FILE="\\path\to\file.xlsx"

set OUT_TXT=out.txt
set PREVIOUS_TXT=previous.txt
if exist %PREVIOUS_TXT% DEL %PREVIOUS_TXT%
if exist %OUT_TXT% COPY %OUT_TXT% %PREVIOUS_TXT%

%XDOC2TXT% -8 %SRC_FILE% > %OUT_TXT%

set CMD_DIFF="C:\Program Files\Gow\bin\diff.exe"
set DIFF_TXT="diff.txt"
if exist %PREVIOUS_TXT% %CMD_DIFF% %OUT_TXT% %PREVIOUS_TXT% > %DIFF_TXT%

echo __START_OF_LOG__
if exist %DIFF_TXT% cat %DIFF_TXT%
echo __END_OF_LOG__

やっていることは単純で、Excelファイルの内容をテキストに変換して一旦保存しておき、次回のExcelファイル確認時に、両者の差分を取り出すだけだ。上記と同じようにログでデリミタを指定しておくと、前回の確認時からの変更点のみが記載された、こんなメールが届くことになる。

29c29
< foo foo@xxxx
---
> foo ○ ○ ○ foo@xxx
44c44
< 人数 14 16 18	
---
> 人数 15 17 19	

これならExcelファイルを開くこと無く、手っ取り早く内容を確認できて便利だ。

なお、ここでdiffの取得には、手元の環境に入っていたgowのコマンドを使った。

Gow (Gnu On Windows) is the lightweight alternative to Cygwin. It uses a convenient NSIS installer that installs over 100 extremely useful open source UNIX applications compiled as native win32 binaries.

Home · bmatzelle/gow Wiki · GitHub

セルのデータ取得

差分のデータなんか要らない、ピンポイントで特定のセルのデータだけ分かれば良いというケースもある。そこでRubyからExcelファイルを読み込むためのライブラリであるRooを使ってセルの値を抽出した。

Roo implements read access for all common spreadsheet types.

GitHub - roo-rb/roo: Roo provides an interface to spreadsheets of several sorts.

Excelファイルのセルの値を取り出す処理は下記の通り。Rubyでたった2行で済む手軽さだ。Jenkinsからはこのスクリプトを呼び出す。ログからメールで通知する処理は、上記と同様に行えば良い。

require "roo"
xlsx = Roo::Spreadsheet.open('file.xlsx')
puts xlsx.sheet(0).cell(2,2)

たった1行のメールでも必要なデータさえ載っていれば、価値ある情報となる。退屈な事務作業も、少しばかりの小道具を使うと楽に片付けることが出来るという一例でした。