Commit f0aa54e0fbce27600aa02a1ee5465e2ab5c18ccc
1 parent
1479f172
Exists in
master
and in
4 other branches
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.
Showing
3 changed files
with
237 additions
and
0 deletions
Show diff stats
... | ... | @@ -0,0 +1,20 @@ |
1 | +namespace :gitlab do | |
2 | + namespace :wiki do | |
3 | + | |
4 | + # This task will migrate all of the existing Wiki | |
5 | + # content stored in your database into the new | |
6 | + # Gollum Wiki system. A new repository named | |
7 | + # namespace/project.wiki.git will be created for | |
8 | + # each project that currently has Wiki pages in | |
9 | + # the database. | |
10 | + # | |
11 | + # Notes: | |
12 | + # * The existing Wiki content will remain in your | |
13 | + # database in-tact. | |
14 | + desc "GITLAB | Migrate Wiki content from database to Gollum repositories." | |
15 | + task :migrate => :environment do | |
16 | + wiki_migrator = WikiToGollumMigrator.new | |
17 | + wiki_migrator.migrate! | |
18 | + end | |
19 | + end | |
20 | +end | ... | ... |
... | ... | @@ -0,0 +1,103 @@ |
1 | +class WikiToGollumMigrator | |
2 | + | |
3 | + attr_reader :projects | |
4 | + | |
5 | + def initialize | |
6 | + @projects = [] | |
7 | + | |
8 | + Project.find_in_batches(batch_size: 50) do |batch| | |
9 | + batch.each { |p| @projects << p if p.wikis.any? } | |
10 | + end | |
11 | + end | |
12 | + | |
13 | + def migrate! | |
14 | + projects.each do |project| | |
15 | + log "\nMigrating Wiki for '#{project.path_with_namespace}'" | |
16 | + wiki = create_gollum_repo(project) | |
17 | + create_pages project, wiki | |
18 | + log "Project '#{project.path_with_namespace}' migrated. " + "[OK]".green | |
19 | + end | |
20 | + end | |
21 | + | |
22 | + private | |
23 | + | |
24 | + def create_gollum_repo(project) | |
25 | + GollumWiki.new(project, nil).wiki | |
26 | + end | |
27 | + | |
28 | + def create_pages(project, wiki) | |
29 | + pages = project.wikis.group(:slug).all | |
30 | + | |
31 | + pages.each do |page| | |
32 | + create_page_and_revisions(project, page) | |
33 | + end | |
34 | + end | |
35 | + | |
36 | + def create_page_and_revisions(project, page) | |
37 | + # Grab all revisions of the page | |
38 | + revisions = project.wikis.where(slug: page.slug).ordered.all | |
39 | + | |
40 | + # Remove the first revision created from the array | |
41 | + # and use it to create the Gollum page. Each successive revision | |
42 | + # will then be applied to the new Gollum page as an update. | |
43 | + first_rev = revisions.pop | |
44 | + | |
45 | + wiki = GollumWiki.new(project, page.user) | |
46 | + wiki_page = WikiPage.new(wiki) | |
47 | + | |
48 | + attributes = extract_attributes_from_page(first_rev) | |
49 | + | |
50 | + if wiki_page.create(attributes) | |
51 | + log " Created page '#{wiki_page.title}' " + "[OK]".green | |
52 | + | |
53 | + # Reverse the revisions to create them in the correct | |
54 | + # chronological order. | |
55 | + create_revisions(project, wiki_page, revisions.reverse) | |
56 | + else | |
57 | + log " Failed to create page '#{wiki_page.title}' " + "[FAILED]".red | |
58 | + end | |
59 | + end | |
60 | + | |
61 | + def create_revisions(project, page, revisions) | |
62 | + revisions.each do |revision| | |
63 | + log " Creating revisions..." | |
64 | + # Reinitialize a new GollumWiki instance for each page | |
65 | + # and revision created so the correct User is shown in | |
66 | + # the commit message. | |
67 | + wiki = GollumWiki.new(project, revision.user) | |
68 | + wiki_page = wiki.find_page(page.slug) | |
69 | + | |
70 | + attributes = extract_attributes_from_page(revision) | |
71 | + | |
72 | + content = attributes[:content] | |
73 | + | |
74 | + if wiki_page.update(content) | |
75 | + log " Created revision " + "[OK]".green | |
76 | + else | |
77 | + log " Failed to create revision " + "[FAILED]".red | |
78 | + end | |
79 | + end | |
80 | + end | |
81 | + | |
82 | + def extract_attributes_from_page(page) | |
83 | + attributes = page.attributes | |
84 | + .with_indifferent_access | |
85 | + .slice(:title, :content) | |
86 | + | |
87 | + # Change 'index' pages to 'home' pages to match Gollum standards | |
88 | + if attributes[:title].downcase == "index" | |
89 | + attributes[:title] = "home" unless home_already_exists?(project) | |
90 | + end | |
91 | + | |
92 | + attributes | |
93 | + end | |
94 | + | |
95 | + def home_already_exists?(project) | |
96 | + project.wikis.where(title: 'home').any? || project.wikis.where(title: 'Home').any? | |
97 | + end | |
98 | + | |
99 | + def log(message) | |
100 | + puts message | |
101 | + end | |
102 | + | |
103 | +end | ... | ... |
... | ... | @@ -0,0 +1,114 @@ |
1 | +require "spec_helper" | |
2 | + | |
3 | +describe WikiToGollumMigrator do | |
4 | + | |
5 | + def create_wiki_for(project) | |
6 | + 3.times { @pages[project.id] << create_page(project) } | |
7 | + end | |
8 | + | |
9 | + def create_revisions_for(project) | |
10 | + @pages[project.id].each do |page| | |
11 | + create_revision(page) | |
12 | + end | |
13 | + end | |
14 | + | |
15 | + def create_page(project) | |
16 | + page = project.wikis.new(title: "Page #{rand(1000)}", content: "Content") | |
17 | + page.user = project.owner | |
18 | + page.slug = page.title.parameterize | |
19 | + page.save! | |
20 | + page | |
21 | + end | |
22 | + | |
23 | + def create_revision(page) | |
24 | + revision = page.dup | |
25 | + revision.content = "Updated Content" | |
26 | + revision.save! | |
27 | + end | |
28 | + | |
29 | + def create_temp_repo(path) | |
30 | + FileUtils.mkdir_p path | |
31 | + command = "git init --quiet --bare #{path};" | |
32 | + system(command) | |
33 | + end | |
34 | + | |
35 | + before do | |
36 | + @repo_path = "#{Rails.root}/tmp/test-git-base-path" | |
37 | + @projects = [] | |
38 | + @pages = Hash.new {|h,k| h[k] = Array.new } | |
39 | + | |
40 | + @projects << create(:project) | |
41 | + @projects << create(:project) | |
42 | + | |
43 | + @projects.each do |project| | |
44 | + create_wiki_for project | |
45 | + create_revisions_for project | |
46 | + end | |
47 | + | |
48 | + @project_without_wiki = create(:project) | |
49 | + end | |
50 | + | |
51 | + context "Before the migration" do | |
52 | + it "has two projects with valid wikis" do | |
53 | + @projects.each do |project| | |
54 | + pages = project.wikis.group(:slug).all | |
55 | + pages.count.should == 3 | |
56 | + end | |
57 | + end | |
58 | + | |
59 | + it "has two revision for each page" do | |
60 | + @projects.each do |project| | |
61 | + @pages[project.id].each do |page| | |
62 | + revisions = project.wikis.where(slug: page.slug) | |
63 | + revisions.count.should == 2 | |
64 | + end | |
65 | + end | |
66 | + end | |
67 | + end | |
68 | + | |
69 | + describe "#initialize" do | |
70 | + it "finds all projects that have existing wiki pages" do | |
71 | + Project.count.should == 3 | |
72 | + subject.projects.count.should == 2 | |
73 | + end | |
74 | + end | |
75 | + | |
76 | + context "#migrate!" do | |
77 | + before do | |
78 | + Gitlab::Shell.any_instance.stub(:add_repository) do |path| | |
79 | + create_temp_repo("#{@repo_path}/#{path}.git") | |
80 | + end | |
81 | + | |
82 | + subject.stub(:log).as_null_object | |
83 | + | |
84 | + subject.migrate! | |
85 | + end | |
86 | + | |
87 | + it "creates a new Gollum Wiki for each project" do | |
88 | + @projects.each do |project| | |
89 | + wiki_path = project.path_with_namespace + ".wiki.git" | |
90 | + full_path = @repo_path + "/" + wiki_path | |
91 | + File.exist?(full_path).should be_true | |
92 | + File.directory?(full_path).should be_true | |
93 | + end | |
94 | + end | |
95 | + | |
96 | + it "creates a gollum page for each unique Wiki page" do | |
97 | + @projects.each do |project| | |
98 | + wiki = GollumWiki.new(project, nil) | |
99 | + wiki.pages.count.should == 3 | |
100 | + end | |
101 | + end | |
102 | + | |
103 | + it "creates a new revision for each old revision of the page" do | |
104 | + @projects.each do |project| | |
105 | + wiki = GollumWiki.new(project, nil) | |
106 | + wiki.pages.each do |page| | |
107 | + page.versions.count.should == 2 | |
108 | + end | |
109 | + end | |
110 | + end | |
111 | + end | |
112 | + | |
113 | + | |
114 | +end | ... | ... |