Skip to content

Instantly share code, notes, and snippets.

@nbudin
Forked from reidab/gist:98009
Created May 7, 2009 16:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nbudin/108202 to your computer and use it in GitHub Desktop.
Save nbudin/108202 to your computer and use it in GitHub Desktop.
[submodule "octopi"]
path = octopi
url = git://github.com/fcoury/octopi.git
require 'open-uri'
require 'csv'
require 'rubygems'
require 'hpricot'
module GoogleCode
class IssueReader
DEBUG = true
CSV_COLUMNS = %w(ID Type Component Status Priority Summary Modified Milestone Owner Stars Opened Closed BlockedOn Blocking Blocked MergedInto Reporter Cc)
def initialize(project)
@base_url = "http://code.google.com/p/#{project}/issues"
end
def read
@issues = read_csv
@issues.each do |id,issue|
issue.merge!(read_extra_issue_details(id))
end
end
def issues
@issues ||= read
end
protected
def read_extra_issue_details(id)
puts "Reading issue details for issue #{id}"
issue = {}
issue_doc = Hpricot(read_path("detail?id=#{id}"))
issue[:description] = issue_doc.search("//td.issuedescription/pre").inner_html
issue[:comments] = []
issue_doc.search('//td.issuecomment/.author/..').each do |comment|
issue[:comments] << {
:author => comment.search('.author/a:last').inner_html,
:body => comment.search('pre').inner_html,
:time => DateTime.parse(comment.search('.date').first.attributes['title'])
}
end
issue[:labels] = []
issue_doc.search('//a.label').each do |label|
next if CSV_COLUMNS.include?(label.search('b').inner_html[0..-2])
issue[:labels] << label.inner_text
end
issue
end
def read_csv
path = "csv?can=1&sort=id&colspec=#{CSV_COLUMNS.join('+')}"
puts "Reading CSV file" if DEBUG
issues = {}
CSV.parse(read_path(path)) do |row|
next if row[0] == 'ID'
issue = {}
row.each_with_index do |field,i|
issue[GoogleCode::Support::underscore(CSV_COLUMNS[i]).to_sym] = field.to_s.empty? ? nil : \
case CSV_COLUMNS[i]
when 'ID', 'Stars', 'MergedInto'
field.to_i
when 'Component', 'Cc'
field.to_s.split(',').map{|m| m.strip}
when 'Opened', 'Closed', 'Modified'
DateTime.parse(field.to_s)
when 'Blocked'
field.to_s == "Yes"
else
field.to_s
end
issues[row[0].to_i] = issue
end
end
return issues
end
# Reads data from a path relative to the base Google Code URL
# for the project's issues.
def read_path(path)
url = "#{@base_url}/#{path}"
puts "Fetching URL: #{url}" if DEBUG
begin
open(url).read
rescue OpenURI::HTTPError => e
puts "HTTP Error: #{e}"
return ""
end
end
end
module Support
def self.underscore(camel_cased_word)
camel_cased_word.to_s.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end
end
require 'google_code'
require 'octopi/lib/octopi'
include Octopi
if ARGV.length < 2
puts "Usage: import.rb <google-code-project> <github-project>"
exit 1
end
reader = GoogleCode::IssueReader.new("procon")
issues = reader.issues
authenticated do |g|
repo = g.repository(ARGV[1])
issues.each do |id, issue|
next if id == 0
puts "Importing issue #{id}"
gh_body = issue[:description]
gh_body << "\n\nReported by #{issue[:reporter]} at #{issue[:opened].strftime("%Y-%m-%d %H:%M:S")}"
gh_body << "Imported from Google Code issue number #{id}"
gh_issue = repo.open_issue :title => issue[:summary], :body => gh_body
gh_labels = issue[:labels].dup
if issue[:type] and issue[:type].strip.length > 0
gh_labels.push(issue[:type].downcase)
end
if issue[:milestone] and issue[:milestone].strip.length > 0
gh_labels.push(issue[:milestone].downcase)
end
gh_issue.add_label(*gh_labels)
issue[:comments].each do |comment|
gh_comment = comment[:body]
gh_comment << "\n\n-- #{comment[:author]}, #{comment[:time].strftime("%Y-%m-%d %H:%M:%S")}"
gh_issue.comment(gh_comment)
end
if issue[:status] == "Fixed"
gh_issue.close
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment