crontabファイルからドキュメントを生成する試み

コマンドの定時実行をするときにお世話になるcrontabの設定ファイルから、ジョブの実行時刻や頻度をドキュメンテーションするツール@piyoppi/cron2docsを作ってみました。

※まだ絶賛開発中です。十分に検証できていないこと、および今後仕様が変更されるかもしれないことをご容赦ください。

構造

以下のようなモジュールで構成されています(図をクリックで拡大)。

class diagram

crontabファイルから実行日時を取得し、かつ何らかの方法でコメントを生成してJSON形式のドキュメントを出力する cron2json-docs-generatorモジュールを中心に構成されています。

cron2json-docs-generator はJavaScriptオブジェクト形式でドキュメントを出力するので、これを見やすいフォーマットに変換する周辺モジュール(たとえばMarkdown形式に変換する docs-display-table)を自由に実装することができます。

コメントの抽出

cron2json-docs-generatorモジュールは、crontabファイルを入力に受け取り、スケジュール情報をパースしてJSON形式に変換します。 また、crontabファイルに記述されている定時実行コマンドからコメント(タイトルと概要説明)を抽出し、スケジュール情報と対応させます。 コメント生成器として、以下のモジュールを用意しました。

ファイルからコメントを抽出するモジュール (comment-generator-file)

実行ファイルがスクリプト形式の場合、そのスクリプトには以下のようなコメントが書いてあるとします。 スクリプトのコメントを抽出して利用できれば、コードとドキュメントが近いところに配置され、コードの変更に伴ってドキュメントが更新されることを期待できそうです。

#!/bin/bash
#
#  クリーンアップタスク
#
#  テンポラリディレクトリにある1日前に作成したファイルを削除します。
#

... スクリプトが続く ...

comment-generator-file モジュールは、実行ファイルからコメントを抽出してドキュメントとします。

まずは、 filename-extractor モジュールを使って、実行コマンドからファイルパスを抽出します。 このモジュールは、ファイルパスのリストの中からコマンドに一致するファイルパスを返却します。

comment-generator-file

抽出したファイルパスを用いて、 comment-extractor モジュールでファイルの中身からコメントを抽出します。 たとえばシェルスクリプトの場合は comment-generator-file モジュールが comment-extractor-sh モジュールにファイルの中身を渡し、以下のように処理します。

  • ファイルのはじめのコメントの1行目をタイトルとする
  • ファイルのはじめのコメントの2行目以降を概要とする

先に示したスクリプトの場合、以下のように抽出されます。

  • タイトル:クリーンアップタスク
  • 概要:テンポラリディレクトリにある1日前に作成したファイルを削除します。

いまのところ、PHPファイル用のモジュールシェルスクリプト用のモジュールを用意しています。 言語別の comment-extractor モジュールと filename-extractor を実装することで、より多くの実行コマンド形式やスクリプトのフォーマットに対応できます。

YAMLファイルに記述したコメントを対応付けるモジュール (comment-generator-yaml)

comment-generator-yaml

以下のように、実行コマンドとコメントのマッピングをYAMLファイルで定義しておきます。crontabファイルに記述されているコマンドにマッチするように pattern を定義します。マッチした場合は、comment に記載されたコメントと関連付けられます。

commands:
  - pattern: "app_server:nightly-task"               # コマンドに一致するパターンを正規表現で記述
    comment:
      title: "夜間タスク"                             # タイトル
      summary: "アクセス数を集計して保存します。"       # 概要

上記の pattern は、たとえば以下のコマンドにマッチします。

0 1 * * * /bin/bash -l -c 'cd /path/to/tasks && RAILS_ENV=production bundle exec rake app_server:nightly-task --silent'

ドキュメントが生成される際に、このスケジュールと関連付けられてドキュメント化されます。

GitHub Actions アプリケーション

アプリケーションとして、入力にcrontabファイルを受け取り、Markdown形式のドキュメントを出力する actions-cron2docs を実装しました。

(※actions-cron2docs は cron2docs リポジトリの packages/actions-cron2doc モジュールのクローンです。)

- uses: piyoppi/actions-cron2docs@mirrored
  with:
    cron_file: ./path/to/crontab.txt                    # crontabファイル
    output_filename: ./wiki/docs_from_whenever.md       # 出力されるMarkdown
    document_yaml_filename: ./docs/job_docs.yml         # YAML形式のドキュメント
    task_dirs: ${{ github.workspace }}/tasks            # タスクが格納されているディレクトリ
    relative_path_base_dir: ${{ github.workspace }}     # crontab内のコマンドが相対パスで設定されていた時のベースパス

comment-generator-yaml と comment-generator-file をバンドルしており、comment-generator-yaml でコメントを解決した場合はこれを用い、解決しなかった場合は comment-generator-file に処理が渡ります。

各パラメータの意味は以下の通りです。

cron_file (必須パラメータ)

crontabのファイル名を渡します。

output_filename

出力されるMarkdownのファイル名を設定します。

document_yaml_filename

YAML形式のドキュメントを設定します。comment-generator-yaml モジュールで利用されます。

task_dirs

crontabでスケジュール実行するスクリプトが格納されているディレクトリを指定します。comment-generator-file に渡すファイルリストの生成に利用します。

relative_path_base_dir

crontabでスケジュール実行するスクリプトでファイルパスが相対パスで記述されているときのベースパスを指定します。

たとえば、relative_path_base_dir/base と指定したとき、以下のようなスケジュールに対して

0 1 * * * path/to/foo.sh

filename-extractor がファイルを解決するために以下のように補完します。

0 1 * * * /base/path/to/foo.sh

relative_path_base_dir を指定しない場合、 filename-extractor モジュールは相対パスで指定されたコマンドを解析しません。

Workflow例

このActionsを使って、GitHub Wiki のページにドキュメントを反映させるワークフローの例を以下に示します。

name: Update schedule document

on: workflow_dispatch

jobs:
  update-wiki:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - uses: actions/checkout@v3
        with:
          path: wiki

      - uses: piyoppi/actions-cron2docs@mirrored
        with:
          cron_file: ./crontab.txt
          output_filename: ./wiki/docs.md

      - run: |
          git config --global user.email "bot@garakuta-toolbox.com"
          git config --global user.name "piyoppi-bot"
          git add docs.md
          git commit -m 'Update schedule document'
          git push origin master
        working-directory: ./wiki 

たとえば、 上記のようなワークフローを実際に実行すると、GitHub Wikiにドキュメントが設置されます。

まとめ

たくさんあるスケジュールを自動的にドキュメンテーションできたら便利だなという気持ちで作ってみました。実際にこれを運用していくことでツールをアップデートできるといいなと思っています。ではでは~。

このカウンタは @piyoppi/counter-tools を使っています。

クリックすると匿名でいいねできます。