Skip to content

Instantly share code, notes, and snippets.

@petertseng
Created April 10, 2017 11:55
Show Gist options
  • Select an option

  • Save petertseng/04edd07d4b35cda2cbc1d8142b6fcc13 to your computer and use it in GitHub Desktop.

Select an option

Save petertseng/04edd07d4b35cda2cbc1d8142b6fcc13 to your computer and use it in GitHub Desktop.
require 'json'
require 'time'
# Create a personal access token at https://github.com/settings/tokens
# It needs NO scopes.
# In fact, you could just not use a token, but then you get rate-limited to 60 an hour instead of 5000 an hour.
TOKEN_FILE = 'secrets/token.txt'.freeze
SLEEP_TIME = 2
CACHE = 'cache'.freeze
Dir.mkdir(CACHE) unless File.exist?(CACHE)
LAST_REQUEST = [0]
def req(url)
cache = "#{CACHE}/#{url.gsub(/\W/, ?_)}"
if File.exist?(cache)
res = File.read(cache)
else
if Time.now.to_i - LAST_REQUEST.first < SLEEP_TIME
puts "#{url}: sleeping to not overload."
Kernel.sleep(SLEEP_TIME)
end
LAST_REQUEST[0] = Time.now.to_i
tok = File.read(TOKEN_FILE).chomp
res = `curl -H "Authorization: token #{tok}" "#{url}"`
File.open(cache, ?w) { |f| f.puts(res) }
end
JSON.parse(res)
rescue => e
puts res
puts "No parse: #{e}"
end
REPO = ARGV.first
case REPO
when 'xgo'
COMMENT_PAGES = 14
EVENT_PAGES = 31
ISSUE_PAGES = 7
when 'xrust'
COMMENT_PAGES = 11
EVENT_PAGES = 15
ISSUE_PAGES = 3
when 'xhaskell'
COMMENT_PAGES = 12
EVENT_PAGES = 27
ISSUE_PAGES = 6
else raise "Unknown repo #{REPO}"
end
comments = (1..COMMENT_PAGES).flat_map { |page|
req("https://api.github.com/repos/exercism/#{REPO}/issues/comments?per_page=100&page=#{page}")
}
events = (1..EVENT_PAGES).flat_map { |page|
req("https://api.github.com/repos/exercism/#{REPO}/issues/events?per_page=100&page=#{page}").select { |i| %w(closed reopened).include?(i['event']) }
}
issues = (1..ISSUE_PAGES).flat_map { |page|
req("https://api.github.com/repos/exercism/#{REPO}/issues?per_page=100&state=all&page=#{page}").reject { |i| i['pull_request'] }
}.map { |i| [i['url'], i] }.to_h
issues.each_value { |i|
i[:events] = [
# Probot uses 'updated:' search, and this *DOES* take updated_at into account.
# Unfortunately, we only get the most recent update.
# So for issues that were edited after they were closed, we may have false positives.
# (we think it's stale, when it's was not at the time due to an update)
[:fresh, Time.parse(i['updated_at'])],
]
}
comments.each { |c|
next unless (i = issues[c['issue_url']])
i[:events] << [:fresh, Time.parse(c['created_at'])]
# Probot uses 'updated:' search, and this *DOES* take updated_at into account.
# Same caveat as above with only getting the most recent update.
i[:events] << [:fresh, Time.parse(c['updated_at'])]
}
events.each { |e|
next unless (i = issues[e['issue']['url']])
event = case e['event']
when 'closed'; :close
when 'reopened'; :open
else raise "unknown event #{e}"
end
i[:events] << [event, Time.parse(e['created_at'])]
}
DAY = 86400
STALE = 60 * DAY
issues.each_value { |i|
open = true
time = Time.parse(i['created_at'])
stale = false
check = ->(etime) { stale ||= open && etime - time >= STALE }
i[:events].sort_by(&:last).each { |event, etime|
case event
when :fresh; check[etime]
when :close; check[etime]; open = false
when :open; open = true
else raise "Unknown event #{event}"
end
time = etime
}
check[Time.now]
next unless stale
puts "%3d %s" % i.values_at('number', 'title')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment