nadoka/nadoka

View on GitHub
plugins/githubissuesbot.nb

Summary

Maintainability
Test Coverage
# -*-ruby; coding: utf-8 -*- vim:set ft=ruby:
# Copyright (C) 2013 Kazuhiro NISHIYAMA
#
# This program is free software with ABSOLUTELY NO WARRANTY.
# You can re-distribute and/or modify this program under
# the same terms of the Ruby's license.
#

=begin

== Configuration:

  BotConfig << {
    :name => :GithubIssuesBot,
    :bot_name => 'gh',
    :ch => '#nadoka_check',
    :tm => 30, # min
    #:nkf => "--oc=CP50221 --ic=UTF-8 --fb-xml",
    :owner => "nadoka",
    :repo => "nadoka",
  }

=end
require 'open-uri'
require 'time'
begin
  require 'json'
rescue LoadError
  require 'rubygems'
  require 'json'
end

module GithubIssues
  module_function

  DEFAULT_HEADER = {
    'User-Agent' => "Nadoka-GithubIssuesBot/0.1",
  }

  def uri_read(uri, header)
    debug = $GITHUB_ISSUES_DEBUG
    p uri if debug
    uri.open("r", header) do |f|
      p f.meta if debug
      return f.read
    end
  rescue OpenURI::HTTPError => e
    p e.io.meta if debug
    if e.io.meta["x-ratelimit-remaining"] == "0"
      raise "#{e}: because x-ratelimit-remaining=0"
    end
    raise "#{e}: #{uri}"
  end

  def issues(owner, repo, since, state='open', header=DEFAULT_HEADER)
    since = since.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
    uri = URI("https://api.github.com/repos/#{owner}/#{repo}/issues?since=#{since}&state=#{state}")
    json = uri_read(uri, header)
    issues = JSON.parse(json)
    issues.each do |issue|
      comments_uri = URI("#{issue['comments_url']}?since=#{since}")
      json = uri_read(comments_uri, header)
      comments = JSON.parse(json)
      if comments.empty?
        yield [:issue, issue, issue_to_s(issue)]
      else
        comments.each do |comment|
          yield [:comment, comment, comment_to_s(comment, issue)]
        end
      end
    end
  end

  def user_to_s(user)
    return unless user
    "@#{user['login']} "
  end

  def time_to_s(time)
    return unless time
    time = Time.parse(time)
    time.localtime.strftime("%H:%M ")
  end

  def issue_to_s(issue)
    return unless issue
    "#{issue['html_url']} [#{issue['state']}] #{time_to_s(issue['updated_at'])}#{user_to_s(issue['user'])}#{issue['title']}"
  end

  def comment_to_s(comment, issue=nil)
    return unless comment
    if issue
      info = "[#{issue['state']}] "
    else
    end
    "#{comment['html_url']} #{info}#{time_to_s(comment['updated_at'])}#{user_to_s(comment['user'])}#{comment['body']}"
  end
end

if __FILE__ == $0
  $GITHUB_ISSUES_DEBUG = $DEBUG
  owner = "rubima"
  repo = "rubima"
  since = Time.now - 60*60*3*7
  GithubIssues.issues(owner, repo, since) do |_, _, s|
    puts s.gsub(/\s+/, ' ')
  end
  GithubIssues.issues(owner, repo, since, 'close') do |_, _, s|
    puts s.gsub(/\s+/, ' ')
  end
  exit
end

require 'nkf'

class GithubIssuesBot < Nadoka::NDK_Bot
  def bot_initialize
    @ch = @bot_config.fetch(:ch, '#nadoka_check')
    @tm = @bot_config.fetch(:tm, 30) # min
    @prevtm = Time.now
    @nkf_options = @bot_config.fetch(:nkf, "--oc=CP50221 --ic=UTF-8 --fb-xml")
    @owner = @bot_config.fetch(:owner, "nadoka")
    @repo = @bot_config.fetch(:repo, "nadoka")
  end

  def bot_state
    nt = Time.at(@prevtm.to_i + @tm * 60)
    "<#{self.class}: next check at #{nt.asctime}@#{@ch}>" 
  end

  def send_notice(ch, msg)
    msg = msg.gsub(/\s+/, ' ')
    if @nkf_options
      msg = NKF.nkf(@nkf_options, msg)
    end
    super(ch, msg)
  end

  def on_timer tm
    check
  end

  def check
    tm = Time.now
    if tm.to_i - @tm * 60 > @prevtm.to_i
      make_notice tm
    end
  end

  def make_notice tm
    since = @prevtm
    @prevtm = tm
    GithubIssues.issues(@owner, @repo, since) do |_, _, s|
      send_notice @ch, s
    end
    GithubIssues.issues(@owner, @repo, since, 'close') do |_, _, s|
      send_notice @ch, s
    end
  rescue Exception => e
    send_notice(@ch, "github issues bot error for #{@owner}/#{@repo}: #{e}")
    @manager.ndk_error e
  end
end