Python
CI
オフライン

オフラインで動作する祝日かどうかを判定してCIをスキップさせるPythonスクリプト

ローカルファイルに記載した日付と一致するかどうかを判定して、祝日などにCIをスキップできるシンプルなPythonスクリプトの実装方法と使用方法を記載します。


背景

現在CIで使用しているクラウドサービス上のVMは、稼働時間で課金されるため、休日や祝日などの使用しない日は起動させたくない。しかし、クラウドサービスで設定できるのは、土日などの決まった曜日だけなので、祝日や特定の日付などに起動をスキップできなかった。

内閣府のデータを使用して祝日かどうかを判定できるメンテナンスフリーなツールを公開してくださっている方がすでにいますが、会社独自の休日への対応や、外部のネットワークに依存せずに祝日を判定したかった。

そこで、オフラインで判定できるスクリプトを作成しました。


動作確認環境


  • python 2.6.6, 3.7.1

  • CentOS release 6.8

  • Windows 10 version 1809


実装方法

以下のisholiday.pyholidays.txtを同一ディレクトリに配置します。


isholiday.py

"""

Check whether holiday or not based on holidays.txt.
"""

import sys, os

def get_holidays_list():
holidays_list = []
target_path = os.path.join(os.path.dirname(__file__), 'holidays.txt')
with open(target_path, 'r') as f:
for row in f:
holidays_list.append(row.strip())
return holidays_list

def is_holiday(date):
if date in get_holidays_list():
return True
else:
return False

if __name__ == '__main__':
if len(sys.argv) >= 2:
if is_holiday(sys.argv[1]):
print("It's a holiday!")
sys.exit(0)
else:
print("It's a business day!")
sys.exit(1)
else:
print('Usage: python isHoliday.py `date --iso-8601`')
sys.exit(2)



holidays.txt

2018-07-16

2018-09-17
2018-09-24
2018-10-08
2018-11-23
2018-12-24
2018-12-31
2019-01-01
2019-01-02
2019-01-03
2019-01-14
2019-02-11
2019-03-21


使用方法

python isholiday.py <日付>


<日付>はYYYY-MM-DD形式で指定します。



例:

python isholiday.py `date --iso-8601`

実行した日がholidays.txtに含まれている場合は終了コード0を、

含まれていない場合は1を返します。


CIから呼び出す場合:

#!/bin/sh

python /path/to/isholiday.py `date --iso-8601`
if [ "$?" = "0" ]; then
echo "Skip holiday!"
exit 0
fi


新しい祝日を追加する方法

holidays.txtにYYYY-MM-DD形式で追加してください。

不要な行は削除してしまって構いません。


注意: 2018-07-16の行は後述のテストで使っているため、削除してしまうと、テストが失敗します



テストの実行方法

python -m unittest tests.py


tests.py

import unittest

import isholiday

class TestGetHolidaysList(unittest.TestCase):
def test_file_read(self):
self.assertTrue(len(isholiday.get_holidays_list()) > 0)

class TestIsHoliday(unittest.TestCase):
def test_holiday(self):
self.assertTrue(isholiday.is_holiday('2018-07-16'))
def test_not_holiday(self):
self.assertFalse(isholiday.is_holiday('2018-07-17'))

if __name__ == '__main__':
unittest.main()



問題点

この実装方法では、毎年holidays.txtを更新する必要があります。そのため、部署異動などでメンテナンスする人がいなくなったりすると、CIをスキップできなくなります。(可能な限りシンプルに実装していますので、後任の方への引き継ぎは比較的容易だと思います)