diff --git a/lib/heptapod/native_mercurial/migrator.rb b/lib/heptapod/native_mercurial/migrator.rb index f29df4bad5a25823690aca9436e47ad6efcca988_bGliL2hlcHRhcG9kL25hdGl2ZV9tZXJjdXJpYWwvbWlncmF0b3IucmI=..324b6a46e4078e3ac72e7901943f7eb53dc2d44d_bGliL2hlcHRhcG9kL25hdGl2ZV9tZXJjdXJpYWwvbWlncmF0b3IucmI= 100644 --- a/lib/heptapod/native_mercurial/migrator.rb +++ b/lib/heptapod/native_mercurial/migrator.rb @@ -95,6 +95,7 @@ # take care of all startup initializations and final cleanups, # like a Python context manager would. def enter + res = nil try_obtain_exclusive_lease do with_project_readonly do vcs_type_enforcer do @@ -98,7 +99,7 @@ try_obtain_exclusive_lease do with_project_readonly do vcs_type_enforcer do - yield + res = yield end end end @@ -102,6 +103,7 @@ end end end + res end def migrate! @@ -128,9 +130,27 @@ ) end + # ensure all gitlab specific state files are present + def hg_ensure_state_files + renew_exclusive_lease + output, status = @project.repository.hg_call( + ["hpd-ensure-all-gitlab-specific-state-files"], force_system_user: true + ) + raise StandardError, output.strip unless status == 0 + end + + def set_final_vcs_type + @project.vcs_type = 'hg' + timeless_save(@project) + end + + # perform the migration, returning a mapping of errors per type + # + # Most errors will raise an exception instead of being added to + # the return. def do_migrate Gitlab::AppLogger.info( message: "Starting native hg migration", project_id: @project.id, project_full_path: @project.full_path ) @@ -131,8 +151,14 @@ def do_migrate Gitlab::AppLogger.info( message: "Starting native hg migration", project_id: @project.id, project_full_path: @project.full_path ) + errors = {} + + rollback_vcs_type = true + hg_ensure_state_files + migrate_merge_requests + rollback_vcs_type = false migrate_issues @@ -137,4 +163,3 @@ migrate_issues - migrate_merge_requests migrate_pipelines @@ -140,3 +165,2 @@ migrate_pipelines - migrate_notes migrate_releases @@ -142,2 +166,4 @@ migrate_releases + errors[:notes] = migrate_notes + set_final_vcs_type @@ -143,14 +169,6 @@ - # ensure all gitlab specific state files are present - renew_exclusive_lease - output, status = @project.repository.hg_call( - ["hpd-ensure-all-gitlab-specific-state-files"], force_system_user: true - ) - raise StandardError, output.strip unless status == 0 - - @project.vcs_type = 'hg' - timeless_save(@project) + errors rescue StandardError => err msg = "Native mercurial migration failed: #{err}" log_error(err, msg) raise @@ -153,7 +171,9 @@ rescue StandardError => err msg = "Native mercurial migration failed: #{err}" log_error(err, msg) raise + ensure + set_final_vcs_type unless rollback_vcs_type end def migrate_issues @@ -201,6 +221,7 @@ def migrate_notes count = 0 + failed = [] @project.notes.each do |note| count += 1 renew_exclusive_lease if count % EXCLUSIVE_LEASE_NOTES_RENEWAL_RATE == 0 @@ -211,5 +232,5 @@ end rescue StandardError => err log_error(err, "Failed to migrate Note id=#{note.id}") - raise + failed << note.id end @@ -215,4 +236,5 @@ end + failed end def migrate_note_positions(note) diff --git a/lib/tasks/migrate/migrate_to_native_hg.rake b/lib/tasks/migrate/migrate_to_native_hg.rake index f29df4bad5a25823690aca9436e47ad6efcca988_bGliL3Rhc2tzL21pZ3JhdGUvbWlncmF0ZV90b19uYXRpdmVfaGcucmFrZQ==..324b6a46e4078e3ac72e7901943f7eb53dc2d44d_bGliL3Rhc2tzL21pZ3JhdGUvbWlncmF0ZV90b19uYXRpdmVfaGcucmFrZQ== 100644 --- a/lib/tasks/migrate/migrate_to_native_hg.rake +++ b/lib/tasks/migrate/migrate_to_native_hg.rake @@ -33,8 +33,12 @@ check_gitaly_connection check_hgitaly_connection migrator = Heptapod::NativeMercurial::Migrator.new(project, user) - migrator.migrate! - puts 'done!'.color(:green) + errors = migrator.migrate! + if errors.each_value.all? { |errs| errs.empty? } + puts 'done!'.color(:green) + else + puts "there are errors for #{errors}. Please check application log for details".color(:yellow) + end end end end diff --git a/spec/lib/heptapod/native_mercurial/migrator_spec.rb b/spec/lib/heptapod/native_mercurial/migrator_spec.rb index f29df4bad5a25823690aca9436e47ad6efcca988_c3BlYy9saWIvaGVwdGFwb2QvbmF0aXZlX21lcmN1cmlhbC9taWdyYXRvcl9zcGVjLnJi..324b6a46e4078e3ac72e7901943f7eb53dc2d44d_c3BlYy9saWIvaGVwdGFwb2QvbmF0aXZlX21lcmN1cmlhbC9taWdyYXRvcl9zcGVjLnJi 100644 --- a/spec/lib/heptapod/native_mercurial/migrator_spec.rb +++ b/spec/lib/heptapod/native_mercurial/migrator_spec.rb @@ -291,6 +291,42 @@ end end + describe '#do_migrate' do + it "sets VCS Type to native even if there are errors if Merge Requests are migrated" do + error = StandardError.new("oops") + expect(subject).to receive(:migrate_issues).and_raise(error) + expect { subject.do_migrate }.to raise_error(error) + expect(project.vcs_type).to eq('hg') + end + + it "does not set VCS Type to native if Merge Requests are not migrated" do + error = StandardError.new("oops") + expect(subject).to receive(:migrate_merge_requests).and_raise(error) + expect { subject.do_migrate }.to raise_error(error) + expect(project.vcs_type).to eq('hg_git') + end + + context "about Notes" do + let!(:issue) do + create(:issue, + project: project, + description: "Sample description", + title: "Sample title") + end + + let!(:my_comment) do + create(:note_on_issue, project: project, noteable: issue, + note: "Sample comment") + end + + it "returns errors" do + expect(subject).to receive(:migrate_note_positions) + .and_raise(StandardError.new('failed')) + expect(subject.migrate!).to eq({ notes: [my_comment.id] }) + end + end + end + # Best approximation to equality of timestamps # # True equality of timestamps is probably impossible, because