開発以外の仕事でやってるちょっとした自動化の紹介

こんにちは、Misocaのとよし(@toyoshi)です。

この記事は、Misoca Advent Calendar 2017 の9日目の記事です。

年末ですね。今年1番驚いた話は、グルテンフリーをやってみようと思ってお米+専用の粉でパンが作れるホームベーカリーを買ったところ、専用の粉というのがグルテンパウダー(例えばこういうの)だったことです。ホームベーカリーを買って箱を開けたときに本当に恥ずかしい気持ちになりました。

さて、私の苦手なものに、手順が曖昧であったり、何かを思い出すストレスというものがあります。なので、繰り返し発生する作業は「自動化できないか?」「そもそもやらなくていいのではないか?」ということを考えてるようにしています。そして、自動化できるものは自動化し、それが難しくてもマニュアル化することで次回以降に自分が記憶喪失になっていても作業ができるようにしています。

今回はそんな私がちょっとした自動化でやっていることを紹介します。

定型のSlackでの発言

月に一回などの繰り返しのタスクの後、担当者にSlackで報告するという作業があります。

何も工夫しないと、Slackアプリを開いて、決められたチャンネルを思い出し、それをCmd+kで検索して開いて、担当者のアカウント名を思い出して、適切な文章を考えて入力するという流れになります。

これだと頑張っても15秒かかるし、チャンネル名とアカウント名を記憶しておかないといけないし、文章も考えないといけないのでかなりのエネルギーを消耗します。

そこで、Slackにメッセージを送信するスクリプトを作り、作業マニュアルに定型文を書いておくことでTerminalにコピペで報告が終わるようにしています。

できること

コマンドラインからSlackに投稿できる

image.png

image.png

どうやってるか

投稿スクリプトを用意してパスを通しておきます。

require 'slack'
require 'dotenv'

Dotenv.load

message = ARGV[0]
channel_name = ARGV[1] || 'current_toyoshi'

Slack.configure do |config|
    config.token = ENV['SLACK_API_TOKEN']
end

Slack.chat_postMessage(text: message, channel: channel_name)

上記がスクリプトを呼び出すためのスクリプト。これをパスが通ってるところにslackという
名前でおいている。

#!/bin/bash

cd ~/projects/slack
bundle exec ruby main.rb "$1" $2

作業マニュアルにコマンドごとテキストを用意しておく

(省略)

完了チェック
[x] 完了画面に表示された価格と、Misoca上の請求額が正しいか

報告
slack "@okumura 口座振替の売り上げ登録が完了しました。。Misocaの方でも請求済みにしてあります。"

ターミナルを立ち上げてコピペするだけなので最初よりかなり簡単になりました。

忘れてはいけないメールのTrelloカード化

自分のところにしか送られて来ないけど、みんなと共有したいメールや、すぐには処理しないけどタスクとして残るメールはTrelloに自動でカード化されるようにしています。
例えば

  • サービスのメンテナンス情報
  • (個人用)メールで送られてくるAmazonギフト券(登録するのをよく忘れてしまう)

などを設定しています。

これも自分でやろうとすると、Trelloを開いたり、どこのボードに書き込むのか思い出したりエネルギーを使いますし、何より忘れてしまうと大変です。

ボードメニュー>もっと見る>メールでボードへ送信するための設定

から設定できます。

あとは、Gmailなどからフィルタを作って転送設定をするだけです。Gmailだと新しい転送メールアドレスを設定するときは不正利用防止のため、一度そのメールアドレスに転送に同意するかどうかのメールが送られますが、それもTrelloがカードにして受け取ってくれます。

勤怠の新規申請、修正の確認と承認作業

有給の申請や、出勤退勤時間の修正などの申請があるとそれを確認して承認するという仕事があります。勤怠管理はWebサービスを使っているのですが、いちいちログインするのは大変なので勤怠申請をSlackに表示するコマンドと、一括で承認するコマンドを作っています。

申請を確認するコマンドを実行すると、勤怠管理システムをスクレイピングしてきてこんな内容がSlackに投稿されます。

image.png

内容をみて問題なければ承認のコマンドを実行します。

image.png

いちいちログインしてたまにしか使わないUIを触らなくていいのは快適です。

日報の作成

Misocaでは全員が日報をesa.ioに書くのが決まりになっています。
これもesaを開いて、日報のテンプレートから新規作成して、今日やったことを思い出して、明日の予定を書くのはエネルギーを使います。そこで自分のGoogleカレンダーから今日と明日の予定を自動でとってきて日報の下書きを作ってくれるコマンドを作って使っています。

require 'date'
require 'esa'
require 'google/apis/calendar_v3'
require 'google/api_client/auth/key_utils'
require 'active_support/all'

distance = ARGV[0] ? ARGV[0].to_i : 1 # 「明日やること」は何日後なのか設定
current_date = ARGV[1] ? DateTime.parse(ARGV[1]).to_date : Date.today

class GCalendar
  def initialize
    key = Google::APIClient::KeyUtils.load_from_pkcs12({YOUR_KEY_PATH}, 'notasecret')
    @calendar_id = 'toyoshi@standfirm.jp'
    @service = Google::Apis::CalendarV3::CalendarService.new
    @service.authorization = Signet::OAuth2::Client.new(
      :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
      :audience => 'https://accounts.google.com/o/oauth2/token',
      :scope => 'https://www.googleapis.com/auth/calendar.readonly',
      :issuer => 'id-617@toyoshi-1357.iam.gserviceaccount.com',
      :signing_key => key
    )
    @service.authorization.fetch_access_token!
  end

  def events(current_date)
    response = @service.list_events(
      @calendar_id,
      order_by: :startTime,
      single_events: true,
      time_min: current_date.beginning_of_day.iso8601,
      time_max: current_date.end_of_day.iso8601
    )

    response.items.map do |event|
      "- [ ] #{event.summary}"
    end
  end
end

calendar = GCalendar.new
todays_events = calendar.events(current_date)
nexts_events = calendar.events(current_date + distance)

category = current_date.strftime('日報/%Y/%m/%d')
name = 'toyoshiの日報'
body = "
## :heartbeat: いまの気持ち

### :speech_balloon:  困ったことや相談したいこと

### :speaker: 他、お知らせしておきたいこと

### :memo: ポエム

### :muscle: 今日やったこと

#{todays_events.join("\n")}

## :rocket: 明日やるつもりのこと

#{nexts_events.join("\n")}

"

client = Esa::Client.new(access_token: ENV['ESA_API_TOKEN'], current_team: ENV['TEAM'])
response = client.posts(q: "name:#{name} category:#{category}")
if response.body['total_count'] == 0
  client.create_post(
    category: category,
    name: name,
    wip: true,
    body_md: body
  )
else
  post_number = response.body['posts'].first['number']
  client.update_post(post_number, body_md: body)
end

これを朝1日の予定を確認したら実行しています。
細かい調整ですが、日報を作ったら日報一覧のページを開くようにしていてすぐに編集できるようにしています。

#!/bin/bash

cd ~/projects/nippou/ 
bundle exec ruby ~/projects/nippou/calendar.rb
sleep 1
open 'https://{team_name}.esa.io/posts?q=toyoshi%E3%81%AE%E6%97%A5%E5%A0%B1&s=created&o=desc' #ここで日報一覧ページを開く

結果

なお、テンプレートから自動で同じエントリを毎日作るだけならこちらもおすすめです。standfirm/esa_feeder: esaの記事をテンプレートから自動作成するアプリケーションです

他の人の日報の確認

Misocaは今20人ぐらいが毎日日報を書いています。それらを全員分を読むには少し工夫が必要です。そこで、特定の日の日報をタブで自動的に開くのをコマンドにしています。

様子

nippou.gif

コード

引数で何日まえの日報を読みたいか指定して使うようになってます。
openにURLを渡すと既定のブラウザで開いてくれます。

Bundler.require
Dotenv.load

distance = ARGV[0] ? ARGV[0].to_i : 0
current_date = Date.today - distance

query = current_date.strftime('日報/%Y/%m/%d')

client = Esa::Client.new(access_token: ENV['ESA_API_TOKEN'], current_team: ENV['TEAM'])
response = client.posts(q: "in:#{query}")
puts "#{response.body['posts'].size}件の日報がありました"
response.body['posts'].each do |p|
  system %!open "#{p['url']}"!
end

最後に

今回は私がしているちょっとした自動化の例を紹介しました。
Misoca Advent Calendar 2017、明日の担当は @kokuyouwind です。