直近のカレンダータスクにスプリントを割り当てるスクリプト : Notion Tips (152)

はじめに

Notion Tips の第152回目は、直近のカレンダータスクにスプリントを割り当てるスクリプトを解説します。昨日、プロジェクトをスクリプトで管理しなくなったので、他の人にも使ってもらえるものになったと思って公開するものです。Make with Notion Showcase Tokyo でスプリントについて質問された時に、近いうちに記事にしますと話していたのですが、少し遅れてしまいました。すみません。

私のタスク管理

基本的に GTD をベースにしていますが、授業や会議など他の業種の方に比べてカレンダータスクが非常に多く存在します。カレンダータスクも当日になれば、次のアクションに相当するタスクになるため、普通のタスクと同様に管理したいです。私の場合は、スプリントを週で回しており、その週に該当するカレンダータスクは、スプリントに登録したいと思いました。現状ではそれらをオートメーションで実現することは不可能なので、Notion API を用いた calendar_to_sprint.rb というスクリプトで実現しています。

データベースの準備

Sprints

今は簡単にスプリントが生成できるようになりましたが、最初はテンプレートから複製しないと作成できませんでした。当時英語のものしかなかったので、私の Sprints は英語版です。日本語版で生成した場合には、この後のスクリプトの名称などを修正する必要があるので、うまく読み替えてください。

Sprints database

ここで重要なのが、weed_id です。その週の月曜日が何周目かを示す年度と週番号を用意しています。もし、日曜始まりでスプリントを実装している人は「yyyy-ww」になります。後で解説するスクリプトでは、この Formula のタイトルを Sprint name にそのまま設定するようにします。

formatDate(prop("Dates"), "GGGG-WW")

Tasks

タスクデータベースに入っているカレンダータスクのうち、現在および次の Sprint のものはこのように Task が結びついていることがわかります。

Tasks database

これら個別のタスクにも week_id が存在しています。ただし、タスクの日付はカレンダーに結びついており、時刻情報が含まれています。ここで、Notion API はサーバ側で処理されるため、タイムゾーンを持っていません。設定された時刻は GMT での時刻で計算されてしまうため、日本だと 9 時間だけずれてしまいます。この week_id は基本的に API でしか利用しないので、無理やりに 9 時間を加算してしまっています。

prop("Start date").dateAdd(9, "hours").formatDate("GGGG-WW")

この結果、日曜日の 15 時以降のタスクは日本のブラウザ上では次の週を示していますが、スクリプトで設定したスプリントは正しく今週のものになっています。

日曜日のタスク

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

月曜日のタスク
image.png

作成したスクリプト

こちらが 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

おわりに

昨日、プロジェクトの自動設定を外したので、スクリプトがだいぶスリム化したため、今回紹介することにしました。このスクリプトが毎日実行されることで、カレンダータスクが入っていれば、直近のスプリントには自動的にタスクが入っていることになります。非常に便利に使っています。

hkob.notion.site