Return to Snippet

Revision: 41533
at February 19, 2011 13:37 by KernelPanic


Initial Code
#!/usr/bin/env ruby
# Trac2Unfuddle: The Unfuddle Trac import tool
# Copyright © 2007-2009, Unfuddle LLC. All rights reserved.
# Author: Joshua W. Frappier
# Version: 0.7
#
# No portion of this code may be duplicated or reproduced
# without the express written consent of Unfuddle LLC.
# For more information, contact [email protected].
#
# NOTE: For this script to work, the following gems must be installed:
#   sqlite3-ruby, xml-simple
#
# NOTE: You MUST change the values in the section below before
# running the script.  Once changed, you can simply run the script
# without any additional parameters:
#
#   ruby project.rb
# this importer is based on the Trac2Unfuddle import tool of Joshua W. Frappier
# Author Gianni Metitieri, Swisstimex
# Version: 1.0

########################################################################
# CHANGE THE VALUES IN THIS SECTION
########################################################################

# change these to your own settings
# be sure that the user is an account administrator
UNFUDDLE_SETTINGS = {
  :subdomain    => 'insert subdomain here',
  :username     => 'insert username here',
  :password     => 'insert password here',
  :ssl          => true  # ssl true or false
}

# values for the newly created Unfuddle project
# NOTE: this project must not currently exist within the specified account
PROJECT_TITLE       = "Imported Project Template"
PROJECT_SHORT_NAME  = "template"
PROJECT_DESCRIPTION = "insert project description here!"
THEME = "blue" #[blue, green, grey, orange, purple, red, teal]

# Define Component
component = ['User Story', 'Documentation', 'Test Case', 'Project Management','Environment','GUI','Database', 'Functionality', 'Performance','Middleware', 'Look & Feel']

# Define Milestones
milestone = ['Backlog', 'Sprint 1', 'Sprint 2', 'Sprint 3']

# Define Milestone Due on
due_on = ['02/28/2010', '11/30/2009', '12/31/2009', '01/31/2010']

# Define Milestone Status
status = [0, 0, 0, 0]

# Define Severity
severity = ['1-Urgent Fix', '2-Must Fix', '3-Should Fix', '4-Could Fix']

# Define Version
version = ['Major.Minor.Patch.Build']

# Define Category
category = ['General','News', 'Project', 'Team', 'Blog']

# Define Customer Field 1
type1 = 'list' # is a list or text
title1 = 'Type' # insert customer title here

if type1 == 'list'
customer_1 = ['BUG', 'REQ', 'TASK', 'TECH']
else
end

# Define Customer Field 2
type2 = 'text' # is a list or text
title2 = 'Effort' # insert customer title here

if type2 == 'list'
customer_2 = ['item1', 'item2', 'item3', 'item4']
else
end

# Define Customer Field 1
type3 = 'text' #is a list or text
title3 = 'Value' # insert customer title here

if type3 == 'list'
customer_3 = ['item1', 'item2', 'item3', 'item4']
else
end

# Define Notebook 
title = 'Project Wiki'

########################################################################
# NO NEED TO CHANGE BELOW THIS LINE
########################################################################
require 'rubygems'
require 'date'
require 'net/https'
require 'xmlsimple'

# an adequate hash to xml conversion method
class Hash
  def to_xml(options={})
    xml = ''
    xml += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" unless options[:skip_instruct]
    xml += "<#{options[:root]}>" if options[:root]
    self.each { |key,val|
      key_formatted = key.to_s.gsub('_','-')
      case val
      when Date:
        val_formatted = val.strftime("%Y-%m-%d")
      when DateTime, Time:
        val_formatted = val.strftime("%Y-%m-%d %H:%M:%S")
      when Hash:
        val_formatted = val.to_xml(:skip_instruct => true)
      else
        val_formatted = val.to_s.gsub('&', '&amp;').gsub('>', '&gt;').gsub('<', '&lt;')
      end
      xml += "<#{key_formatted}>"
      xml += val_formatted.to_s
      xml += "</#{key_formatted}>"
    }
    xml += "</#{options[:root]}>" if options[:root]
    xml
  end
end

# convenience method to get a date
class Time
  def to_date
    ::Date.new(year, month, day)
  end
end

# get a resource
# returns a hash of the resource
def api_get_hash(short_url)
  request = Net::HTTP::Get.new("/api/v1/#{short_url}.xml", {'Accept' => 'application/xml'})
  request.basic_auth UNFUDDLE_SETTINGS[:username], UNFUDDLE_SETTINGS[:password]
  response = @http.request(request)
  if response.code == "200"
    XmlSimple.xml_in(response.body, { 'ForceArray' => false })
  else
    {}
  end
end

# create a resource via the unfuddle api and return the
# new id of the resource on success
def api_create(resource_type, short_url, attributes)
  request = Net::HTTP::Post.new("/api/v1/#{short_url}", {'Accept' => 'application/xml', 'Content-type' => 'application/xml'})
  request.basic_auth UNFUDDLE_SETTINGS[:username], UNFUDDLE_SETTINGS[:password]
  request.body = attributes.to_xml(:root => resource_type)
  response = @http.request(request)
  if response.code == "201"
    response['Location'].split('/').last.to_i
  else
    puts "ERROR (#{response.code}):\n" + response.body
    0
  end
end

# update a resource via the unfuddle api
def api_update(resource_type, short_url, attributes)
  request = Net::HTTP::Put.new("/api/v1/#{short_url}", {'Accept' => 'application/xml', 'Content-type' => 'application/xml'})
  request.basic_auth UNFUDDLE_SETTINGS[:username], UNFUDDLE_SETTINGS[:password]
  request.body = attributes.to_xml(:root => resource_type)
  response = @http.request(request)
  if response.code == "200"
    true
  else
    puts "ERROR (#{response.code}):\n" + response.body
    false
  end
end

# upload a file to the unfuddle api
# returns the upload key of the file
def api_upload(short_url, path)
  request = Net::HTTP::Post.new("/api/v1/#{short_url}.xml", {'Accept' => 'application/xml', 'Content-type' => 'application/octet-stream'})
  request.basic_auth UNFUDDLE_SETTINGS[:username], UNFUDDLE_SETTINGS[:password]
  path = path.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) } unless File.exists?(path)
  request.body = File.read(path)
  response = @http.request(request)
  if response.code == "200"
    XmlSimple.xml_in(response.body, { 'ForceArray' => false })['key']
  else
    nil
  end
end

# setup the http object for later use
@http = Net::HTTP.new("#{UNFUDDLE_SETTINGS[:subdomain]}.unfuddle.com", UNFUDDLE_SETTINGS[:ssl] ? 443 : 80)
@http.use_ssl = true if UNFUDDLE_SETTINGS[:ssl]
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE if UNFUDDLE_SETTINGS[:ssl]


# create the project
print "Creating Project..."
project_id = api_create(:project, 'projects', {:title => PROJECT_TITLE, :short_name => PROJECT_SHORT_NAME, :description => PROJECT_DESCRIPTION, :assignee_on_resolve => 'reporter',:close_ticket_simultaneously_default => 0, :enable_time_tracking => 1, :theme => THEME,
  :ticket_field1_active => 1, :ticket_field1_title => title1, :ticket_field1_disposition => type1,
  :ticket_field2_active => 1, :ticket_field2_title => title2, :ticket_field2_disposition => type2,
  :ticket_field3_active => 1, :ticket_field3_title => title3, :ticket_field3_disposition => type3})
print "#{project_id}...done\n"

# create the components
index = 0
while index < component.length
  print "Creating Component #{component[index]}..."
  component_id = api_create(:component, "projects/#{project_id}/components", {:name => component[index]})
  print "#{component_id}...done\n"
  index += 1
end

# create milestones
index = 0
while index < milestone.length
  print "Creating Milestone #{milestone[index]}..."
  milestone_id = api_create(:milestone, "projects/#{project_id}/milestones", {:title => milestone[index], :due_on => Date.parse(due_on[index]).to_s, :completed => status[index]})
  print "#{milestone_id}...done\n"
  index += 1
end


# create severities
index = 0
while index < severity.length
  print "Creating Severities #{severity[index]}..."
  severity_id = api_create(:severity, "projects/#{project_id}/severities", {:name => severity[index]})
  print "#{severity_id}...done\n"
  index += 1
end

# create versions
index = 0
while index < version.length
  print "Creating Versions #{version[index]}..."
  version_id = api_create(:version, "projects/#{project_id}/versions", {:name => version[index]})
  print "#{version_id}...done\n"
  index += 1
end

# create customer field 1
if type1 == 'list'
index = 0
while index < customer_1.length
  print "Creating Customer Field 1 #{customer_1[index]}..."
  customer_1_id = api_create(:custom_field_value, "projects/#{project_id}/custom_field_values", {:value => customer_1[index], :field_number => 1})
  print "#{customer_1_id}...done\n"
  index += 1
end
else
end

# create customer field 2
if type2 == 'list'
index = 0
while index < customer_2.length
  print "Creating Customer Field 2 #{customer_2[index]}..."
  customer_2_id = api_create(:custom_field_value, "projects/#{project_id}/custom_field_values", {:value => customer_2[index], :field_number => 2})
  print "#{customer_2_id}...done\n"
  index += 1
end
else
end

# create customer field 3
if type3 == 'list'
index = 0
while index < customer_3.length
  print "Creating Customer Field 3 #{customer_3[index]}..."
  customer_3_id = api_create(:custom_field_value, "projects/#{project_id}/custom_field_values", {:value => customer_3[index], :field_number => 3})
  print "#{customer_3_id}...done\n"
  index += 1
end
else
end

# create category 
index = 0
while index < category.length
  print "Creating category #{category[index]}..."
  category_id = api_create(:category, "projects/#{project_id}/categories", {:name => category[index]})
  print "#{category_id}...done\n"
  index += 1
end


# create notebook
print "Creating Notebook..."
notebook_id = api_create(:notebook, "projects/#{project_id}/notebooks", {:title => title})
print "#{notebook_id}...done\n"

Initial URL


Initial Description
Written by Joshua W. Frappier

Initial Title
Unfuddle Project template

Initial Tags
template

Initial Language
Ruby