From: Dan Knox Date: Mon, 11 Mar 2013 02:10:44 +0000 (-0700) Subject: Create Wiki migration task. X-Git-Tag: v5.0.0~59^2~1^2~3 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=f0aa54e0fbce27600aa02a1ee5465e2ab5c18ccc;p=wvm%2Fgitlab.git Create Wiki migration task. This commit adds a new Rake task for migrating all of your existing Wiki content from your database into new Gollum repositories. The bulk of the logic happens within the `WikiToGollumMigrator` class which is decently test covered and located in the lib directory. The new Rake task can be executed by running: `bundle exec rake gitlab:wiki:migrate` It will output a nice log of every project that it migrates along with success or failure messages. I have used it on my own installation to migrate my Wikis successfully. --- diff --git a/lib/tasks/gitlab/migrate_wiki.rake b/lib/tasks/gitlab/migrate_wiki.rake new file mode 100644 index 000000000..9b2f34c6b --- /dev/null +++ b/lib/tasks/gitlab/migrate_wiki.rake @@ -0,0 +1,20 @@ +namespace :gitlab do + namespace :wiki do + + # This task will migrate all of the existing Wiki + # content stored in your database into the new + # Gollum Wiki system. A new repository named + # namespace/project.wiki.git will be created for + # each project that currently has Wiki pages in + # the database. + # + # Notes: + # * The existing Wiki content will remain in your + # database in-tact. + desc "GITLAB | Migrate Wiki content from database to Gollum repositories." + task :migrate => :environment do + wiki_migrator = WikiToGollumMigrator.new + wiki_migrator.migrate! + end + end +end diff --git a/lib/wiki_to_gollum_migrator.rb b/lib/wiki_to_gollum_migrator.rb new file mode 100644 index 000000000..6083533b7 --- /dev/null +++ b/lib/wiki_to_gollum_migrator.rb @@ -0,0 +1,103 @@ +class WikiToGollumMigrator + + attr_reader :projects + + def initialize + @projects = [] + + Project.find_in_batches(batch_size: 50) do |batch| + batch.each { |p| @projects << p if p.wikis.any? } + end + end + + def migrate! + projects.each do |project| + log "\nMigrating Wiki for '#{project.path_with_namespace}'" + wiki = create_gollum_repo(project) + create_pages project, wiki + log "Project '#{project.path_with_namespace}' migrated. " + "[OK]".green + end + end + + private + + def create_gollum_repo(project) + GollumWiki.new(project, nil).wiki + end + + def create_pages(project, wiki) + pages = project.wikis.group(:slug).all + + pages.each do |page| + create_page_and_revisions(project, page) + end + end + + def create_page_and_revisions(project, page) + # Grab all revisions of the page + revisions = project.wikis.where(slug: page.slug).ordered.all + + # Remove the first revision created from the array + # and use it to create the Gollum page. Each successive revision + # will then be applied to the new Gollum page as an update. + first_rev = revisions.pop + + wiki = GollumWiki.new(project, page.user) + wiki_page = WikiPage.new(wiki) + + attributes = extract_attributes_from_page(first_rev) + + if wiki_page.create(attributes) + log " Created page '#{wiki_page.title}' " + "[OK]".green + + # Reverse the revisions to create them in the correct + # chronological order. + create_revisions(project, wiki_page, revisions.reverse) + else + log " Failed to create page '#{wiki_page.title}' " + "[FAILED]".red + end + end + + def create_revisions(project, page, revisions) + revisions.each do |revision| + log " Creating revisions..." + # Reinitialize a new GollumWiki instance for each page + # and revision created so the correct User is shown in + # the commit message. + wiki = GollumWiki.new(project, revision.user) + wiki_page = wiki.find_page(page.slug) + + attributes = extract_attributes_from_page(revision) + + content = attributes[:content] + + if wiki_page.update(content) + log " Created revision " + "[OK]".green + else + log " Failed to create revision " + "[FAILED]".red + end + end + end + + def extract_attributes_from_page(page) + attributes = page.attributes + .with_indifferent_access + .slice(:title, :content) + + # Change 'index' pages to 'home' pages to match Gollum standards + if attributes[:title].downcase == "index" + attributes[:title] = "home" unless home_already_exists?(project) + end + + attributes + end + + def home_already_exists?(project) + project.wikis.where(title: 'home').any? || project.wikis.where(title: 'Home').any? + end + + def log(message) + puts message + end + +end diff --git a/spec/lib/wiki_to_gollum_migrator_spec.rb b/spec/lib/wiki_to_gollum_migrator_spec.rb new file mode 100644 index 000000000..a784d836d --- /dev/null +++ b/spec/lib/wiki_to_gollum_migrator_spec.rb @@ -0,0 +1,114 @@ +require "spec_helper" + +describe WikiToGollumMigrator do + + def create_wiki_for(project) + 3.times { @pages[project.id] << create_page(project) } + end + + def create_revisions_for(project) + @pages[project.id].each do |page| + create_revision(page) + end + end + + def create_page(project) + page = project.wikis.new(title: "Page #{rand(1000)}", content: "Content") + page.user = project.owner + page.slug = page.title.parameterize + page.save! + page + end + + def create_revision(page) + revision = page.dup + revision.content = "Updated Content" + revision.save! + end + + def create_temp_repo(path) + FileUtils.mkdir_p path + command = "git init --quiet --bare #{path};" + system(command) + end + + before do + @repo_path = "#{Rails.root}/tmp/test-git-base-path" + @projects = [] + @pages = Hash.new {|h,k| h[k] = Array.new } + + @projects << create(:project) + @projects << create(:project) + + @projects.each do |project| + create_wiki_for project + create_revisions_for project + end + + @project_without_wiki = create(:project) + end + + context "Before the migration" do + it "has two projects with valid wikis" do + @projects.each do |project| + pages = project.wikis.group(:slug).all + pages.count.should == 3 + end + end + + it "has two revision for each page" do + @projects.each do |project| + @pages[project.id].each do |page| + revisions = project.wikis.where(slug: page.slug) + revisions.count.should == 2 + end + end + end + end + + describe "#initialize" do + it "finds all projects that have existing wiki pages" do + Project.count.should == 3 + subject.projects.count.should == 2 + end + end + + context "#migrate!" do + before do + Gitlab::Shell.any_instance.stub(:add_repository) do |path| + create_temp_repo("#{@repo_path}/#{path}.git") + end + + subject.stub(:log).as_null_object + + subject.migrate! + end + + it "creates a new Gollum Wiki for each project" do + @projects.each do |project| + wiki_path = project.path_with_namespace + ".wiki.git" + full_path = @repo_path + "/" + wiki_path + File.exist?(full_path).should be_true + File.directory?(full_path).should be_true + end + end + + it "creates a gollum page for each unique Wiki page" do + @projects.each do |project| + wiki = GollumWiki.new(project, nil) + wiki.pages.count.should == 3 + end + end + + it "creates a new revision for each old revision of the page" do + @projects.each do |project| + wiki = GollumWiki.new(project, nil) + wiki.pages.each do |page| + page.versions.count.should == 2 + end + end + end + end + + +end