はじめに
Notion Tips の第152回目は、直近のカレンダータスクにスプリントを割り当てるスクリプトを解説します。昨日、プロジェクトをスクリプトで管理しなくなったので、他の人にも使ってもらえるものになったと思って公開するものです。Make with Notion Showcase Tokyo でスプリントについて質問された時に、近いうちに記事にしますと話していたのですが、少し遅れてしまいました。すみません。
私のタスク管理
基本的に GTD をベースにしていますが、授業や会議など他の業種の方に比べてカレンダータスクが非常に多く存在します。カレンダータスクも当日になれば、次のアクションに相当するタスクになるため、普通のタスクと同様に管理したいです。私の場合は、スプリントを週で回しており、その週に該当するカレンダータスクは、スプリントに登録したいと思いました。現状ではそれらをオートメーションで実現することは不可能なので、Notion API を用いた calendar_to_sprint.rb というスクリプトで実現しています。
データベースの準備
Sprints
今は簡単にスプリントが生成できるようになりましたが、最初はテンプレートから複製しないと作成できませんでした。当時英語のものしかなかったので、私の Sprints は英語版です。日本語版で生成した場合には、この後のスクリプトの名称などを修正する必要があるので、うまく読み替えてください。

ここで重要なのが、weed_id です。その週の月曜日が何周目かを示す年度と週番号を用意しています。もし、日曜始まりでスプリントを実装している人は「yyyy-ww」になります。後で解説するスクリプトでは、この Formula のタイトルを Sprint name にそのまま設定するようにします。
formatDate(prop("Dates"), "GGGG-WW")
Tasks
タスクデータベースに入っているカレンダータスクのうち、現在および次の Sprint のものはこのように Task が結びついていることがわかります。

これら個別のタスクにも week_id が存在しています。ただし、タスクの日付はカレンダーに結びついており、時刻情報が含まれています。ここで、Notion API はサーバ側で処理されるため、タイムゾーンを持っていません。設定された時刻は GMT での時刻で計算されてしまうため、日本だと 9 時間だけずれてしまいます。この week_id は基本的に API でしか利用しないので、無理やりに 9 時間を加算してしまっています。
prop("Start date").dateAdd(9, "hours").formatDate("GGGG-WW")
この結果、日曜日の 15 時以降のタスクは日本のブラウザ上では次の週を示していますが、スクリプトで設定したスプリントは正しく今週のものになっています。

逆にこの加算をしないと、月曜日の 9時前のタスクは前のスプリントのタスクになってしまっていました。この補正をすることで、正しく翌週のスプリントに設定されていることがわかります。


作成したスクリプト
こちらが calendar_to_sprint.rb です。NotionRubyMapping を利用しています。なお、スプリントの日付の設定は、現在は次のスプリントの日付については、自動更新が設定してくれるので必要はないのですが、せっかく作ったので残したままにしています。スクリプトはそれほど難しいことはやっていないので、個々の行についての解説は省略します。
#! /usr/bin/env ruby require "date" require "notion_ruby_mapping" include NotionRubyMapping NotionRubyMapping.configure { |c| c.token = ENV["NOTION_API_KEY"] } SPRINT_DATABASE_ID = "ここにスプリントデータベースのIDを入れます" sprint_db = Database.find SPRINT_DATABASE_ID sp = sprint_db.properties today = Date.today cwday = today.cwday monday = today + (8 - cwday) sunday = monday + 6 next_sprint = sprint_db.query_database(sp["Sprint status"].filter_equals("Next")).first nsdp = next_sprint.properties["Dates"] next_sprint_week_key = if nsdp.start_date.nil? nsdp.start_date = monday nsdp.end_date = sunday next_sprint.save next_sprint.properties["week_id"].formula["string"] else next_sprint.properties["week_id"].formula["string"] end next_sprint_title = next_sprint.title if next_sprint_week_key != next_sprint_title next_sprint.properties["Sprint name"].text_objects.rich_text_objects = next_sprint_week_key next_sprint.save end TASK_DATABASE_ID = "ここにタスクDBのIDを入れます" task_db = Database.find TASK_DATABASE_ID tp = task_db.properties query = tp["Start date"].filter_on_or_before(sunday) .and(tp["Sprint"].filter_is_empty) .ascending(tp["Start date"]) checked_sprint = {next_sprint_week_key => next_sprint} unsettled_tasks = task_db.query_database(query) unsettled_tasks.each do |task| week_id = task.properties["week_id"].formula["string"] sprint = checked_sprint[week_id] unless sprint sprint = sprint_db.query_database(sp["Sprint name"].filter_equals(week_id)).first checked_sprint[week_id] = sprint end task.properties["Sprint"].relation = [sprint.id] print "set #{task.title} to #{sprint.title}\n" task.save end
スクリプトの自動実行
スクリプト自体は朝7時13分に実行されるように cron を設定しています。このマシンは研究室で24時間作動しているので、毎日自動的に実行するようになっています。実際には月曜日に一度だけ実行すればいいのですが、失敗した時のために毎日実行するようにしています。
13 7 * * * /bin/bash -c 'export PATH=/opt/homebrew/bin:$PATH; eval "$(rbenv init -)"; env NOTION_API_KEY=APIキーをここに書きます ruby $HOME/bin/calendar_to_sprint.rb' >> cron.log
おわりに
昨日、プロジェクトの自動設定を外したので、スクリプトがだいぶスリム化したため、今回紹介することにしました。このスクリプトが毎日実行されることで、カレンダータスクが入っていれば、直近のスプリントには自動的にタスクが入っていることになります。非常に便利に使っています。