Skip to content

Instantly share code, notes, and snippets.

@Arthur
Created December 10, 2008 11:02
Show Gist options
  • Save Arthur/34303 to your computer and use it in GitHub Desktop.
Save Arthur/34303 to your computer and use it in GitHub Desktop.
Migration of Retrospectiva tickets to Trac tickets
# Migration of Retrospectiva tickets to Trac tickets
# by arthur.petry@bolloretelecom.eu
#
# Tested with Retrospectiva r351 (Last Changed Date: 2007-12-03) with OpenID (see User#to_s)
# and Trac 0.11.1
#
# Warning : use it with an empty trac.db, we do a TracTicket.delete_all && a TracTicketChange.delete_all
# (in order to keep Ticket ids)
#
# Limitation :
# - attachment are not keeped
# - priority are not the one of trac, but the ones you used in Retrospectiva
# - ...
require 'rubygems'
require 'active_record'
require 'yaml'
require 'logger'
CONFIG = YAML.load(File.read('retro2trac.yml'))
ActiveRecord::Base.logger = Logger.new("retro2trac.log")
class RetrospectivaRecord < ActiveRecord::Base
establish_connection(CONFIG["retro"])
def self.abstract_class?
true
end
end
class Ticket < RetrospectivaRecord
belongs_to :milestone
belongs_to :priority
belongs_to :status
belongs_to :project
belongs_to :assigned_user, :class_name => 'User', :foreign_key => 'assigned_user_id'
belongs_to :user
has_many :ticket_changes, :order => 'created_at'
has_one :attachment, :as => :attachable
has_and_belongs_to_many :ticket_properties, :include => [:ticket_property_type], :uniq => true
#["id", "milestone_id", "priority_id", "status_id", "author", "summary", "content", "author_host", "created_at", "project_id", "assigned_user_id", "approved", "spam", "email", "updated_at", "user_id"]
def component
ticket_properties.detect{|p| p.ticket_property_type.name == "Component"}
end
def release
ticket_properties.detect{|p| p.ticket_property_type.name == "Release"}
end
def to_trac_attributes
{
:type => "", # the ticket purpose
:time => created_at.to_i, # the time it was created
:changetime => updated_at.to_i,
:component => component && component.name,
:severity => "",
:priority => priority && priority.name,
:owner => assigned_user.to_s, # who is this ticket assigned to
:reporter => user.to_s,
:cc => "", # email addresses to notify
:version => release && release.name,
:milestone => milestone && milestone.name,
:status => status && ((status.name == "Open") && ((assigned_user && "assigned") || "new") || "closed"),
:resolution => status && (status.name != "Open") && status.name.downcase || "",
:summary => summary, # one-line summary
:description => content, # problem description (long)
:keywords => "retro",
}
end
end
class Milestone < RetrospectivaRecord
end
class Priority < RetrospectivaRecord
end
class Project < RetrospectivaRecord
has_many :tickets
end
class Status < RetrospectivaRecord
set_table_name "status"
end
class TicketChange < RetrospectivaRecord
#["id", "ticket_id", "author", "content", "created_at", "changes", "approved", "spam", "email", "user_id"
belongs_to :ticket
belongs_to :user
serialize :changes, Hash
RETRO_TO_TRAC_CHANGES = {
"Assigned user" => "owner",
"Component" => "component",
"Milestone" => "milestone",
"Priority" => "priority",
"Release" => "version",
"Status" => "Resolution"
}
def to_trac_attributes
result = {
:ticket => ticket_id,
:time => created_at.to_i,
:author => user.to_s,
}
# cleanup comments :
content.gsub!(/\[(#\d+)\]/,'\1') # [#123] => #123
content.gsub!(/\[(r\d+)\]/,'\1') # [r234] => r123
results = []
results << result.merge(:field => "comment", :newvalue => content) unless content.blank?
changes.keys.each do |key|
if RETRO_TO_TRAC_CHANGES[key]
oldvalue = changes[key][:old]
newvalue = changes[key][:new]
if key == "Status"
oldvalue.downcase!
newvalue.downcase!
end
results << result.merge(
:field => RETRO_TO_TRAC_CHANGES[key],
:oldvalue => oldvalue,
:newvalue => newvalue
)
else
logger.error "don't know what do to do with changes #{id} : #{key}"
end
end
results
end
end
class TicketProperty < RetrospectivaRecord
belongs_to :ticket_property_type
end
class TicketPropertyType < RetrospectivaRecord
end
class User < RetrospectivaRecord
def to_s
identity_url
end
end
# require 'pp'
# pp Ticket.find(:all).map(&:status).map(&:name).uniq.sort
# ["Duplicate", "Fixed", "Invalid", "Open", "WontFix", "WorksForMe"]
# ticket = Ticket.find(:first)
# pp ticket.status && ticket.status.name
# pp ticket.to_trac_attributes
# pp ticket.ticket_changes.map(&:content)
# pp ticket.ticket_changes.map(&:to_trac_attributes)
# exit
# Resolution - Reason for why a ticket was closed. One of fixed, invalid, wontfix, duplicate, worksforme.
# Status - What is the current status? One of new, assigned, closed, reopened.
class TracRecord < ActiveRecord::Base
establish_connection(CONFIG["trac"])
end
class TracTicket < TracRecord
set_table_name "ticket"
def self.inheritance_column
nil # in order to use the "type" column...
end
end
class TracTicketChange < TracRecord
set_table_name "ticket_change"
end
## Do the Migration
TracTicket.delete_all
TracTicketChange.delete_all
project = Project.find_by_name(CONFIG["project"]["name"])
project.tickets.find(:all).each do |ticket|
trac_ticket = TracTicket.new(ticket.to_trac_attributes)
trac_ticket.id = ticket.id
trac_ticket.save
ticket.ticket_changes.map(&:to_trac_attributes).flatten.each do |change|
TracTicketChange.create(change)
end
end
retro:
adapter: mysql
database: retrospectiva
username: root
password:
encoding: utf8
trac:
adapter: sqlite3
database: trac.db
project:
name: myProject
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment