diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 421ab545d9a..a758a09aae5 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.47.0 +0.48.0 diff --git a/Gemfile b/Gemfile index 6c9834d7d27..8c5c2ac739f 100644 --- a/Gemfile +++ b/Gemfile @@ -398,7 +398,7 @@ group :ed25519 do end # Gitaly GRPC client -gem 'gitaly-proto', '~> 0.42.0', require: 'gitaly' +gem 'gitaly-proto', '~> 0.45.0', require: 'gitaly' gem 'toml-rb', '~> 0.3.15', require: false diff --git a/Gemfile.lock b/Gemfile.lock index afb0b6b471d..89023b1cbf1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -273,7 +273,7 @@ GEM po_to_json (>= 1.0.0) rails (>= 3.2.0) gherkin-ruby (0.3.2) - gitaly-proto (0.42.0) + gitaly-proto (0.45.0) google-protobuf (~> 3.1) grpc (~> 1.0) github-linguist (4.7.6) @@ -1030,7 +1030,7 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.2.0) - gitaly-proto (~> 0.42.0) + gitaly-proto (~> 0.45.0) github-linguist (~> 4.7.0) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-markup (~> 1.6.2) diff --git a/lib/gitlab/git/wiki.rb b/lib/gitlab/git/wiki.rb index d651c931a38..e7b2f52a552 100644 --- a/lib/gitlab/git/wiki.rb +++ b/lib/gitlab/git/wiki.rb @@ -23,14 +23,14 @@ module Gitlab end def write_page(name, format, content, commit_details) - assert_type!(format, Symbol) - assert_type!(commit_details, CommitDetails) - - gollum_wiki.write_page(name, format, content, commit_details.to_h) - - nil - rescue Gollum::DuplicatePageError => e - raise Gitlab::Git::Wiki::DuplicatePageError, e.message + @repository.gitaly_migrate(:wiki_write_page) do |is_enabled| + if is_enabled + gitaly_write_page(name, format, content, commit_details) + gollum_wiki.clear_cache + else + gollum_write_page(name, format, content, commit_details) + end + end end def delete_page(page_path, commit_details) @@ -110,6 +110,25 @@ module Gitlab raise ArgumentError, "expected a #{klass}, got #{object.inspect}" end end + + def gitaly_wiki_client + @gitaly_wiki_client ||= Gitlab::GitalyClient::WikiService.new(@repository) + end + + def gollum_write_page(name, format, content, commit_details) + assert_type!(format, Symbol) + assert_type!(commit_details, CommitDetails) + + gollum_wiki.write_page(name, format, content, commit_details.to_h) + + nil + rescue Gollum::DuplicatePageError => e + raise Gitlab::Git::Wiki::DuplicatePageError, e.message + end + + def gitaly_write_page(name, format, content, commit_details) + gitaly_wiki_client.write_page(name, format, content, commit_details) + end end end end diff --git a/lib/gitlab/gitaly_client/wiki_service.rb b/lib/gitlab/gitaly_client/wiki_service.rb new file mode 100644 index 00000000000..03afcce81f0 --- /dev/null +++ b/lib/gitlab/gitaly_client/wiki_service.rb @@ -0,0 +1,45 @@ +require 'stringio' + +module Gitlab + module GitalyClient + class WikiService + MAX_MSG_SIZE = 128.kilobytes.freeze + + def initialize(repository) + @gitaly_repo = repository.gitaly_repository + @repository = repository + end + + def write_page(name, format, content, commit_details) + request = Gitaly::WikiWritePageRequest.new( + repository: @gitaly_repo, + name: GitalyClient.encode(name), + format: format.to_s, + commit_details: Gitaly::WikiCommitDetails.new( + name: GitalyClient.encode(commit_details.name), + email: GitalyClient.encode(commit_details.email), + message: GitalyClient.encode(commit_details.message) + ) + ) + + strio = StringIO.new(content) + + enum = Enumerator.new do |y| + until strio.eof? + chunk = strio.read(MAX_MSG_SIZE) + request.content = GitalyClient.encode(chunk) + + y.yield request + + request = Gitaly::WikiWritePageRequest.new + end + end + + response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_write_page, enum) + if error = response.duplicate_error.presence + raise Gitlab::Git::Wiki::DuplicatePageError, error + end + end + end + end +end diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 78fb2df884a..f10d9383ae2 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -180,37 +180,47 @@ describe ProjectWiki do end describe "#create_page" do - after do - destroy_page(subject.pages.first.page) + shared_examples 'creating a wiki page' do + after do + destroy_page(subject.pages.first.page) + end + + it "creates a new wiki page" do + expect(subject.create_page("test page", "this is content")).not_to eq(false) + expect(subject.pages.count).to eq(1) + end + + it "returns false when a duplicate page exists" do + subject.create_page("test page", "content") + expect(subject.create_page("test page", "content")).to eq(false) + end + + it "stores an error message when a duplicate page exists" do + 2.times { subject.create_page("test page", "content") } + expect(subject.error_message).to match(/Duplicate page:/) + end + + it "sets the correct commit message" do + subject.create_page("test page", "some content", :markdown, "commit message") + expect(subject.pages.first.page.version.message).to eq("commit message") + end + + it 'updates project activity' do + subject.create_page('Test Page', 'This is content') + + project.reload + + expect(project.last_activity_at).to be_within(1.minute).of(Time.now) + expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now) + end end - it "creates a new wiki page" do - expect(subject.create_page("test page", "this is content")).not_to eq(false) - expect(subject.pages.count).to eq(1) + context 'when Gitaly wiki_write_page is enabled' do + it_behaves_like 'creating a wiki page' end - it "returns false when a duplicate page exists" do - subject.create_page("test page", "content") - expect(subject.create_page("test page", "content")).to eq(false) - end - - it "stores an error message when a duplicate page exists" do - 2.times { subject.create_page("test page", "content") } - expect(subject.error_message).to match(/Duplicate page:/) - end - - it "sets the correct commit message" do - subject.create_page("test page", "some content", :markdown, "commit message") - expect(subject.pages.first.page.version.message).to eq("commit message") - end - - it 'updates project activity' do - subject.create_page('Test Page', 'This is content') - - project.reload - - expect(project.last_activity_at).to be_within(1.minute).of(Time.now) - expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now) + context 'when Gitaly wiki_write_page is disabled', :skip_gitaly_mock do + it_behaves_like 'creating a wiki page' end end