Sunday, October 26, 2008

[HOWTO]: Trac to Unfuddle migration...

We're testing a number of project management tools. One of the biggest hurdles in changing toolsets is data migration. For our needs, this means: milestones, tickets, wiki/notebook, SCM (SVN/GIT) and users.

Trac as we're using it includes SVN support. We'll be using GIT with Unfuddle.

Now the steps for migration:

  1. Firstly--you'll need git-svn and Ruby on your machine. If you need help getting here leave a specific comment below.
  2. On the input (migrating FROM) side, you'll need a copy of your trac directory (access to the sqlite3 db powering trac) and the credentials for the source SVN server.
  3. On the target (migrating TO) side, you'll need to have your unfuddle subdomain name, credentials and your git ssh keypair organized. Note: Don't create any Unfuddle projects by hand. One of our helper tools requires a clean slate.
  4. We move the trac info before the repository. The trac migration script is restrictive of being the first to create your project, so we're stuck in this order. Get unfuddle's trac2unfuddle.rb helper script. Crack it open and edit the fields for your target unfuddle project name (remember this should be the info for the project you want to create new, NOT an existing one). You'll also need to have the Trac sqlite file handy and fill in its location in trac2unfuddle.rb.
  5. UPDATE We've seen that non-URL friendly characters get URL-encoded on the filenames produced by Trac, but not consistently for the filenames stored in the the Trac db. To fix, we had to add these lines to the trac2unfuddle.rb file after the similar looking line handling spaces:
       path = path.gsub('*', '%2A') unless File.exists?(path)
       path = path.gsub('(', '%28') unless File.exists?(path)
       path = path.gsub(')', '%29') unless File.exists?(path)
    
  6. Run ruby trac2unfuddle.rb and grab a beer TUAW.com rutabaga.
  7. When you return, you'll see an error which should be relatively self-explanatory (you didn't have ruby-sqlite installed and friends) OR you'll now have a fully transitioned set of milestones, tasks, and notebook (the trac wiki). Log into Unfuddle and confirm.
  8. Before you complain--the wiki formatting totally, absolutely sucks. You lose most of the love you put into Trac--even the easy stuff. Somebody please hack a fix to the trac2unfuddle.rb script and send me link to it.
  9. Next up is the repository. You'll need a users.txt to map your svn users (user names) to git users (full names and emails). Read up on it here. You'll want to use the project you just created above to layer the repository onto the project management data in the same project. Log into Unfuddle and navigate to the project you've just created and create a new repository for it using their web interface. Then execute a command set like:
    mkdir svn-source-initial
    cd svn-source-initial
    git-svn init http://the-path-to-the-source-svn-repository/trunk/ --no-metadata
    git config svn.authorsfile users.txt
    git-svn fetch # Go get another tuber time. Entire SVN history coming to you.
    cd ..
    git clone svn-source-initial git-cloned-cleanly
    cd git-cloned-cleanly
    git remote add unfuddle git@subdomain.unfuddle.com:subdomain/projectname.git
    git config remote.unfuddle.push refs/heads/master:refs/heads/master
    git push unfuddle master
    
  10. You'll likely get errors at git-svn fetch because you forgot a username or two. Just add them to the users.txt and restart the fetch command. All that's left is logging into Unfuddle and checking the repository tab.
  11. Success! Congratulations--you have finished your migration. Set your SVN/Trac to readonly for a few days then put it up in S3 and on a DVD and savor your migration to the latest trendy toolsets.

2 comments:

SkinnyBoy said...

This is a great how to.

Did you encounter this error when you were migrating your trac stuff over?
Check the stacktrace

Jonathan Siegel said...

SkinnyBoy--your error looks to be a standard HTTP timeout. Any chance you were having connection issues at the time? If not, I'd add a bit of debugging above the Net::HTTP::Post.new call and try and replicate the call (even a get to the index instead) with your browser. I'd be surprised if it wasn't unrelated to the script.