diff options
author | Francisco Javier López <fjlopez@gitlab.com> | 2018-02-05 17:17:21 +0000 |
---|---|---|
committer | Sean McGivern <sean@mcgivern.me.uk> | 2018-02-05 17:17:21 +0000 |
commit | 27c08a16891193227fc83bf4692b4d31a3b2539f (patch) | |
tree | ecf87006574bee3e9ede3cd3ac9b3ac4bda6f427 | |
parent | 0a30a9ea595530499e2d3ae8062506b0a94eebad (diff) | |
download | gitlab-ce-27c08a16891193227fc83bf4692b4d31a3b2539f.tar.gz |
Allow moving wiki pages from the UI
-rw-r--r-- | Gemfile | 4 | ||||
-rw-r--r-- | app/assets/stylesheets/pages/wiki.scss | 8 | ||||
-rw-r--r-- | app/controllers/projects/wikis_controller.rb | 4 | ||||
-rw-r--r-- | app/helpers/wiki_helper.rb | 18 | ||||
-rw-r--r-- | app/models/project_wiki.rb | 4 | ||||
-rw-r--r-- | app/models/wiki_page.rb | 66 | ||||
-rw-r--r-- | app/views/projects/wikis/_form.html.haml | 8 | ||||
-rw-r--r-- | app/views/projects/wikis/edit.html.haml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/fj-37273-moving-wiki-pages-from-the-ui.yml | 5 | ||||
-rw-r--r-- | config/initializers/gollum.rb | 82 | ||||
-rw-r--r-- | doc/user/project/wiki/img/wiki_move_page_1.png | bin | 0 -> 54550 bytes | |||
-rw-r--r-- | doc/user/project/wiki/img/wiki_move_page_2.png | bin | 0 -> 33535 bytes | |||
-rw-r--r-- | doc/user/project/wiki/index.md | 12 | ||||
-rw-r--r-- | lib/gitlab/git/wiki.rb | 24 | ||||
-rw-r--r-- | locale/gitlab.pot | 135 | ||||
-rw-r--r-- | spec/features/projects/wiki/user_updates_wiki_page_spec.rb | 74 | ||||
-rw-r--r-- | spec/features/projects/wiki/user_views_wiki_page_spec.rb | 3 | ||||
-rw-r--r-- | spec/lib/gitlab/git/wiki_spec.rb | 36 | ||||
-rw-r--r-- | spec/models/wiki_page_spec.rb | 120 |
19 files changed, 567 insertions, 41 deletions
@@ -69,6 +69,10 @@ gem 'net-ldap' # Git Wiki # Required manually in config/initializers/gollum.rb to control load order +# Before updating this gem, check if +# https://github.com/gollum/gollum-lib/pull/292 has been merged. +# If it has, then remove the monkey patch for update_page, rename_page and raw_data_in_committer +# in config/initializers/gollum.rb gem 'gollum-lib', '~> 4.2', require: false # Before updating this gem, check if diff --git a/app/assets/stylesheets/pages/wiki.scss b/app/assets/stylesheets/pages/wiki.scss index d8fec583121..e70a57c2a67 100644 --- a/app/assets/stylesheets/pages/wiki.scss +++ b/app/assets/stylesheets/pages/wiki.scss @@ -6,6 +6,14 @@ } } +.wiki-form { + .edit-wiki-page-slug-tip { + display: inline-block; + max-width: 100%; + margin-top: 5px; + } +} + .title .edit-wiki-header { width: 780px; margin-left: auto; diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index 292e4158f8b..fde96cbd35d 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -54,8 +54,8 @@ class Projects::WikisController < Projects::ApplicationController else render 'edit' end - rescue WikiPage::PageChangedError - @conflict = true + rescue WikiPage::PageChangedError, WikiPage::PageRenameError => e + @error = e render 'edit' end diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb index 815fab9e061..41f9eedd4bd 100644 --- a/app/helpers/wiki_helper.rb +++ b/app/helpers/wiki_helper.rb @@ -21,4 +21,22 @@ module WikiHelper add_to_breadcrumb_dropdown link_to(WikiPage.unhyphenize(dir_or_page).capitalize, project_wiki_path(@project, current_slug)), location: :after end end + + def wiki_page_errors(error) + return unless error + + content_tag(:div, class: 'alert alert-danger') do + case error + when WikiPage::PageChangedError + page_link = link_to s_("WikiPageConflictMessage|the page"), project_wiki_path(@project, @page), target: "_blank" + concat( + (s_("WikiPageConflictMessage|Someone edited the page the same time you did. Please check out %{page_link} and make sure your changes will not unintentionally remove theirs.") % { page_link: page_link }).html_safe + ) + when WikiPage::PageRenameError + s_("WikiEdit|There is already a page with the same title in that path.") + else + error.message + end + end + end end diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index 459d1673125..f6041da986c 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -119,6 +119,8 @@ class ProjectWiki end def delete_page(page, message = nil) + return unless page + wiki.delete_page(page.path, commit_details(:deleted, message, page.title)) update_project_activity @@ -131,6 +133,8 @@ class ProjectWiki end def page_title_and_dir(title) + return unless title + title_array = title.split("/") title = title_array.pop [title, title_array.join("/")] diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index e6254183baf..0f5536415f7 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -1,5 +1,6 @@ class WikiPage PageChangedError = Class.new(StandardError) + PageRenameError = Class.new(StandardError) include ActiveModel::Validations include ActiveModel::Conversion @@ -102,7 +103,7 @@ class WikiPage # The hierarchy of the directory this page is contained in. def directory - wiki.page_title_and_dir(slug).last + wiki.page_title_and_dir(slug)&.last.to_s end # The processed/formatted content of this page. @@ -177,7 +178,7 @@ class WikiPage # Creates a new Wiki Page. # # attr - Hash of attributes to set on the new page. - # :title - The title for the new page. + # :title - The title (optionally including dir) for the new page. # :content - The raw markup content. # :format - Optional symbol representing the # content format. Can be any type @@ -189,7 +190,7 @@ class WikiPage # Returns the String SHA1 of the newly created page # or False if the save was unsuccessful. def create(attrs = {}) - @attributes.merge!(attrs) + update_attributes(attrs) save(page_details: title) do wiki.create_page(title, content, format, message) @@ -204,24 +205,29 @@ class WikiPage # See ProjectWiki::MARKUPS Hash for available formats. # :message - Optional commit message to set on the new version. # :last_commit_sha - Optional last commit sha to validate the page unchanged. - # :title - The Title to replace existing title + # :title - The Title (optionally including dir) to replace existing title # # Returns the String SHA1 of the newly created page # or False if the save was unsuccessful. def update(attrs = {}) last_commit_sha = attrs.delete(:last_commit_sha) + if last_commit_sha && last_commit_sha != self.last_commit_sha - raise PageChangedError.new("You are attempting to update a page that has changed since you started editing it.") + raise PageChangedError end - attrs.slice!(:content, :format, :message, :title) - @attributes.merge!(attrs) - page_details = - if title.present? && @page.title != title - title - else - @page.url_path + update_attributes(attrs) + + if title_changed? + page_details = title + + if wiki.find_page(page_details).present? + @attributes[:title] = @page.url_path + raise PageRenameError end + else + page_details = @page.url_path + end save(page_details: page_details) do wiki.update_page( @@ -255,8 +261,44 @@ class WikiPage page.version.to_s end + def title_changed? + title.present? && self.class.unhyphenize(@page.url_path) != title + end + private + # Process and format the title based on the user input. + def process_title(title) + return if title.blank? + + title = deep_title_squish(title) + current_dirname = File.dirname(title) + + if @page.present? + return title[1..-1] if current_dirname == '/' + return File.join([directory.presence, title].compact) if current_dirname == '.' + end + + title + end + + # This method squishes all the filename + # i.e: ' foo / bar / page_name' => 'foo/bar/page_name' + def deep_title_squish(title) + components = title.split(File::SEPARATOR).map(&:squish) + + File.join(components) + end + + # Updates the current @attributes hash by merging a hash of params + def update_attributes(attrs) + attrs[:title] = process_title(attrs[:title]) if attrs[:title].present? + + attrs.slice!(:content, :format, :message, :title) + + @attributes.merge!(attrs) + end + def set_attributes attributes[:slug] = @page.url_path attributes[:title] = @page.title diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index 4e265bf733a..d285251d06f 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -9,7 +9,13 @@ .form-group .col-sm-12= f.label :title, class: 'control-label-full-width' - .col-sm-12= f.text_field :title, class: 'form-control', value: @page.title + .col-sm-12 + = f.text_field :title, class: 'form-control', value: @page.title + - if @page.persisted? + %span.edit-wiki-page-slug-tip + = icon('lightbulb-o') + = s_("WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title.") + = link_to icon('question-circle'), help_page_path('user/project/wiki/index', anchor: 'moving-a-wiki-page'), target: '_blank' .form-group .col-sm-12= f.label :format, class: 'control-label-full-width' .col-sm-12 diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml index 0d77e5bd16d..9d3d4072027 100644 --- a/app/views/projects/wikis/edit.html.haml +++ b/app/views/projects/wikis/edit.html.haml @@ -1,10 +1,7 @@ - @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout - page_title _("Edit"), @page.title.capitalize, _("Wiki") -- if @conflict - .alert.alert-danger - - page_link = link_to s_("WikiPageConflictMessage|the page"), project_wiki_path(@project, @page), target: "_blank" - = (s_("WikiPageConflictMessage|Someone edited the page the same time you did. Please check out %{page_link} and make sure your changes will not unintentionally remove theirs.") % { page_link: page_link }).html_safe += wiki_page_errors(@error) .wiki-page-header.has-sidebar-toggle %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" } diff --git a/changelogs/unreleased/fj-37273-moving-wiki-pages-from-the-ui.yml b/changelogs/unreleased/fj-37273-moving-wiki-pages-from-the-ui.yml new file mode 100644 index 00000000000..5b5310dcfef --- /dev/null +++ b/changelogs/unreleased/fj-37273-moving-wiki-pages-from-the-ui.yml @@ -0,0 +1,5 @@ +--- +title: Allow moving wiki pages from the UI +merge_request: 16313 +author: +type: fixed diff --git a/config/initializers/gollum.rb b/config/initializers/gollum.rb index 0b86cac51a7..6dfaceb8427 100644 --- a/config/initializers/gollum.rb +++ b/config/initializers/gollum.rb @@ -35,6 +35,88 @@ module Gollum [] end end + + # Remove if https://github.com/gollum/gollum-lib/pull/292 has been merged + def update_page(page, name, format, data, commit = {}) + name = name ? ::File.basename(name) : page.name + format ||= page.format + dir = ::File.dirname(page.path) + dir = '' if dir == '.' + filename = (rename = page.name != name) ? Gollum::Page.cname(name) : page.filename_stripped + + multi_commit = !!commit[:committer] + committer = multi_commit ? commit[:committer] : Committer.new(self, commit) + + if !rename && page.format == format + committer.add(page.path, normalize(data)) + else + committer.delete(page.path) + committer.add_to_index(dir, filename, format, data) + end + + committer.after_commit do |index, _sha| + @access.refresh + index.update_working_dir(dir, page.filename_stripped, page.format) + index.update_working_dir(dir, filename, format) + end + + multi_commit ? committer : committer.commit + end + + # Remove if https://github.com/gollum/gollum-lib/pull/292 has been merged + def rename_page(page, rename, commit = {}) + return false if page.nil? + return false if rename.nil? || rename.empty? + + (target_dir, target_name) = ::File.split(rename) + (source_dir, source_name) = ::File.split(page.path) + source_name = page.filename_stripped + + # File.split gives us relative paths with ".", commiter.add_to_index doesn't like that. + target_dir = '' if target_dir == '.' + source_dir = '' if source_dir == '.' + target_dir = target_dir.gsub(/^\//, '') # rubocop:disable Style/RegexpLiteral + + # if the rename is a NOOP, abort + if source_dir == target_dir && source_name == target_name + return false + end + + multi_commit = !!commit[:committer] + committer = multi_commit ? commit[:committer] : Committer.new(self, commit) + + # This piece only works for multi_commit + # If we are in a commit batch and one of the previous operations + # has updated the page, any information we ask to the page can be outdated. + # Therefore, we should ask first to the current committer tree to see if + # there is any updated change. + raw_data = raw_data_in_committer(committer, source_dir, page.filename) || + raw_data_in_committer(committer, source_dir, "#{target_name}.#{Page.format_to_ext(page.format)}") || + page.raw_data + + committer.delete(page.path) + committer.add_to_index(target_dir, target_name, page.format, raw_data) + + committer.after_commit do |index, _sha| + @access.refresh + index.update_working_dir(source_dir, source_name, page.format) + index.update_working_dir(target_dir, target_name, page.format) + end + + multi_commit ? committer : committer.commit + end + + # Remove if https://github.com/gollum/gollum-lib/pull/292 has been merged + def raw_data_in_committer(committer, dir, filename) + data = nil + + [*dir.split(::File::SEPARATOR), filename].each do |key| + data = data ? data[key] : committer.tree[key] + break unless data + end + + data + end end module Git diff --git a/doc/user/project/wiki/img/wiki_move_page_1.png b/doc/user/project/wiki/img/wiki_move_page_1.png Binary files differnew file mode 100644 index 00000000000..0331c9d3a5c --- /dev/null +++ b/doc/user/project/wiki/img/wiki_move_page_1.png diff --git a/doc/user/project/wiki/img/wiki_move_page_2.png b/doc/user/project/wiki/img/wiki_move_page_2.png Binary files differnew file mode 100644 index 00000000000..a8e0c055051 --- /dev/null +++ b/doc/user/project/wiki/img/wiki_move_page_2.png diff --git a/doc/user/project/wiki/index.md b/doc/user/project/wiki/index.md index c0b8a87f038..d084ee41d8a 100644 --- a/doc/user/project/wiki/index.md +++ b/doc/user/project/wiki/index.md @@ -64,6 +64,18 @@ effect. You can find the **Delete** button only when editing a page. Click on it and confirm you want the page to be deleted. +## Moving a wiki page + +You can move a wiki page from one directory to another by specifying the full +path in the wiki page title in the [edit](#editing-a-wiki-page) form. + +![Moving a page](img/wiki_move_page_1.png) + +![After moving a page](img/wiki_move_page_2.png) + +In order to move a wiki page to the root directory, the wiki page title must +be preceded by the slash (`/`) character. + ## Viewing a list of all created wiki pages Every wiki has a sidebar from which a short list of the created pages can be diff --git a/lib/gitlab/git/wiki.rb b/lib/gitlab/git/wiki.rb index ccdb8975342..daa17fc72cf 100644 --- a/lib/gitlab/git/wiki.rb +++ b/lib/gitlab/git/wiki.rb @@ -25,8 +25,9 @@ module Gitlab @repository.exists? end + # Disabled because of https://gitlab.com/gitlab-org/gitaly/merge_requests/539 def write_page(name, format, content, commit_details) - @repository.gitaly_migrate(:wiki_write_page) do |is_enabled| + @repository.gitaly_migrate(:wiki_write_page, status: Gitlab::GitalyClient::MigrationStatus::DISABLED) do |is_enabled| if is_enabled gitaly_write_page(name, format, content, commit_details) gollum_wiki.clear_cache @@ -47,8 +48,9 @@ module Gitlab end end + # Disable because of https://gitlab.com/gitlab-org/gitlab-ce/issues/42094 def update_page(page_path, title, format, content, commit_details) - @repository.gitaly_migrate(:wiki_update_page) do |is_enabled| + @repository.gitaly_migrate(:wiki_update_page, status: Gitlab::GitalyClient::MigrationStatus::DISABLED) do |is_enabled| if is_enabled gitaly_update_page(page_path, title, format, content, commit_details) gollum_wiki.clear_cache @@ -68,8 +70,9 @@ module Gitlab end end + # Disable because of https://gitlab.com/gitlab-org/gitlab-ce/issues/42039 def page(title:, version: nil, dir: nil) - @repository.gitaly_migrate(:wiki_find_page) do |is_enabled| + @repository.gitaly_migrate(:wiki_find_page, status: Gitlab::GitalyClient::MigrationStatus::DISABLED) do |is_enabled| if is_enabled gitaly_find_page(title: title, version: version, dir: dir) else @@ -192,7 +195,10 @@ module Gitlab assert_type!(format, Symbol) assert_type!(commit_details, CommitDetails) - gollum_wiki.write_page(name, format, content, commit_details.to_h) + filename = File.basename(name) + dir = (tmp_dir = File.dirname(name)) == '.' ? '' : tmp_dir + + gollum_wiki.write_page(filename, format, content, commit_details.to_h, dir) nil rescue Gollum::DuplicatePageError => e @@ -210,7 +216,15 @@ module Gitlab assert_type!(format, Symbol) assert_type!(commit_details, CommitDetails) - gollum_wiki.update_page(gollum_page_by_path(page_path), title, format, content, commit_details.to_h) + page = gollum_page_by_path(page_path) + committer = Gollum::Committer.new(page.wiki, commit_details.to_h) + + # Instead of performing two renames if the title has changed, + # the update_page will only update the format and content and + # the rename_page will do anything related to moving/renaming + gollum_wiki.update_page(page, page.name, format, content, committer: committer) + gollum_wiki.rename_page(page, title, committer: committer) + committer.commit nil end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 075103eb0de..159521a750b 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-01-30 14:59+0100\n" -"PO-Revision-Date: 2018-01-30 14:59+0100\n" +"POT-Creation-Date: 2018-02-05 16:03+0100\n" +"PO-Revision-Date: 2018-02-05 16:03+0100\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: \n" @@ -23,6 +23,11 @@ msgid_plural "%d commits" msgstr[0] "" msgstr[1] "" +msgid "%d commit behind" +msgid_plural "%d commits behind" +msgstr[0] "" +msgstr[1] "" + msgid "%d issue" msgid_plural "%d issues" msgstr[0] "" @@ -157,6 +162,18 @@ msgstr "" msgid "An error occurred while fetching sidebar data" msgstr "" +msgid "An error occurred while getting projects" +msgstr "" + +msgid "An error occurred while loading filenames" +msgstr "" + +msgid "An error occurred while rendering KaTeX" +msgstr "" + +msgid "An error occurred while retrieving calendar activity" +msgstr "" + msgid "An error occurred while retrieving diff" msgstr "" @@ -480,6 +497,24 @@ msgstr "" msgid "CiStatus|running" msgstr "" +msgid "CiVariables|Input variable key" +msgstr "" + +msgid "CiVariables|Input variable value" +msgstr "" + +msgid "CiVariables|Remove variable row" +msgstr "" + +msgid "CiVariable|All environments" +msgstr "" + +msgid "CiVariable|Protected" +msgstr "" + +msgid "CiVariable|Toggle protected" +msgstr "" + msgid "CircuitBreakerApiLink|circuitbreaker api" msgstr "" @@ -791,6 +826,9 @@ msgstr "" msgid "Commits|An error occurred while fetching merge requests data." msgstr "" +msgid "Commits|Commit: %{commitText}" +msgstr "" + msgid "Commits|History" msgstr "" @@ -890,6 +928,9 @@ msgstr "" msgid "Copy URL to clipboard" msgstr "" +msgid "Copy branch name to clipboard" +msgstr "" + msgid "Copy commit SHA to clipboard" msgstr "" @@ -1099,12 +1140,33 @@ msgstr "" msgid "Environments|You don't have any environments right now." msgstr "" +msgid "Error fetching contributors data." +msgstr "" + +msgid "Error fetching labels." +msgstr "" + +msgid "Error fetching network graph." +msgstr "" + msgid "Error fetching refs" msgstr "" +msgid "Error fetching usage ping data." +msgstr "" + msgid "Error occurred when toggling the notification subscription" msgstr "" +msgid "Error saving label update." +msgstr "" + +msgid "Error updating status for all todos." +msgstr "" + +msgid "Error updating todo status." +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "" @@ -1716,12 +1778,6 @@ msgstr "" msgid "PipelineSchedules|Inactive" msgstr "" -msgid "PipelineSchedules|Input variable key" -msgstr "" - -msgid "PipelineSchedules|Input variable value" -msgstr "" - msgid "PipelineSchedules|Next Run" msgstr "" @@ -1731,9 +1787,6 @@ msgstr "" msgid "PipelineSchedules|Provide a short description for this pipeline" msgstr "" -msgid "PipelineSchedules|Remove variable row" -msgstr "" - msgid "PipelineSchedules|Take ownership" msgstr "" @@ -2116,6 +2169,9 @@ msgstr[1] "" msgid "Snippets" msgstr "" +msgid "Something went wrong on our end" +msgstr "" + msgid "Something went wrong on our end." msgstr "" @@ -2424,6 +2480,18 @@ msgstr "" msgid "There are problems accessing Git storage: " msgstr "" +msgid "There was an error saving your notification settings." +msgstr "" + +msgid "There was an error when reseting email token." +msgstr "" + +msgid "There was an error when subscribing to this label." +msgstr "" + +msgid "There was an error when unsubscribing from this label." +msgstr "" + msgid "This directory" msgstr "" @@ -2635,6 +2703,9 @@ msgstr "" msgid "Trigger this manual action" msgstr "" +msgid "Type %{value} to confirm:" +msgstr "" + msgid "Unable to reset project cache." msgstr "" @@ -2719,6 +2790,12 @@ msgstr "" msgid "WikiClone|Start Gollum and edit locally" msgstr "" +msgid "WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title." +msgstr "" + +msgid "WikiEdit|There is already a page with the same title in that path." +msgstr "" + msgid "WikiEmptyPageError|You are not allowed to create wiki pages" msgstr "" @@ -2897,6 +2974,9 @@ msgstr[1] "" msgid "mrWidget|Cancel automatic merge" msgstr "" +msgid "mrWidget|Check out branch" +msgstr "" + msgid "mrWidget|Checking ability to merge automatically" msgstr "" @@ -2906,9 +2986,27 @@ msgstr "" msgid "mrWidget|Cherry-pick this merge request in a new merge request" msgstr "" +msgid "mrWidget|Closed" +msgstr "" + msgid "mrWidget|Closed by" msgstr "" +msgid "mrWidget|Closes" +msgstr "" + +msgid "mrWidget|Did not close" +msgstr "" + +msgid "mrWidget|Email patches" +msgstr "" + +msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the" +msgstr "" + +msgid "mrWidget|Mentions" +msgstr "" + msgid "mrWidget|Merge" msgstr "" @@ -2921,6 +3019,9 @@ msgstr "" msgid "mrWidget|Merged by" msgstr "" +msgid "mrWidget|Plain diff" +msgstr "" + msgid "mrWidget|Refresh" msgstr "" @@ -2936,6 +3037,9 @@ msgstr "" msgid "mrWidget|Remove source branch" msgstr "" +msgid "mrWidget|Request to merge" +msgstr "" + msgid "mrWidget|Resolve conflicts" msgstr "" @@ -2981,9 +3085,18 @@ msgstr "" msgid "mrWidget|This project is archived, write access has been disabled" msgstr "" +msgid "mrWidget|You can merge this merge request manually using the" +msgstr "" + msgid "mrWidget|You can remove source branch now" msgstr "" +msgid "mrWidget|command line" +msgstr "" + +msgid "mrWidget|into" +msgstr "" + msgid "mrWidget|to be merged automatically when the pipeline succeeds" msgstr "" diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index 949d90a50ff..4d2a08afecc 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' -describe 'User updates wiki page' do +# Remove skip_gitaly_mock flag when gitaly_update_page implements moving pages +describe 'User updates wiki page', :skip_gitaly_mock do let(:user) { create(:user) } before do @@ -143,6 +144,7 @@ describe 'User updates wiki page' do expect(page).to have_field('wiki[message]', with: 'Update home') fill_in(:wiki_content, with: 'My awesome wiki!') + click_button('Save changes') expect(page).to have_content('Home') @@ -151,4 +153,74 @@ describe 'User updates wiki page' do end end end + + context 'when the page is in a subdir' do + let!(:project) { create(:project, namespace: user.namespace) } + let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) } + let(:page_name) { 'page_name' } + let(:page_dir) { "foo/bar/#{page_name}" } + let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: page_dir, content: 'Home page' }) } + + before do + visit(project_wiki_edit_path(project, wiki_page)) + end + + it 'moves the page to the root folder' do + fill_in(:wiki_title, with: "/#{page_name}") + + click_button('Save changes') + + expect(current_path).to eq(project_wiki_path(project, page_name)) + end + + it 'moves the page to other dir' do + new_page_dir = "foo1/bar1/#{page_name}" + + fill_in(:wiki_title, with: new_page_dir) + + click_button('Save changes') + + expect(current_path).to eq(project_wiki_path(project, new_page_dir)) + end + + it 'remains in the same place if title has not changed' do + original_path = project_wiki_path(project, wiki_page) + + fill_in(:wiki_title, with: page_name) + + click_button('Save changes') + + expect(current_path).to eq(original_path) + end + + it 'can be moved to a different dir with a different name' do + new_page_dir = "foo1/bar1/new_page_name" + + fill_in(:wiki_title, with: new_page_dir) + + click_button('Save changes') + + expect(current_path).to eq(project_wiki_path(project, new_page_dir)) + end + + it 'can be renamed and moved to the root folder' do + new_name = 'new_page_name' + + fill_in(:wiki_title, with: "/#{new_name}") + + click_button('Save changes') + + expect(current_path).to eq(project_wiki_path(project, new_name)) + end + + it 'squishes the title before creating the page' do + new_page_dir = " foo1 / bar1 / #{page_name} " + + fill_in(:wiki_title, with: new_page_dir) + + click_button('Save changes') + + expect(current_path).to eq(project_wiki_path(project, "foo1/bar1/#{page_name}")) + end + end end diff --git a/spec/features/projects/wiki/user_views_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_page_spec.rb index ff325aeadd3..e37436838fd 100644 --- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_page_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' -describe 'User views a wiki page' do +# Remove skip_gitaly_mock flag when gitaly_update_page implements moving pages +describe 'User views a wiki page', :skip_gitaly_mock do let(:user) { create(:user) } let(:project) { create(:project, namespace: user.namespace) } let(:wiki_page) do diff --git a/spec/lib/gitlab/git/wiki_spec.rb b/spec/lib/gitlab/git/wiki_spec.rb new file mode 100644 index 00000000000..bd8dbf07fa7 --- /dev/null +++ b/spec/lib/gitlab/git/wiki_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe Gitlab::Git::Wiki do + let(:project) { create(:project) } + let(:user) { project.owner } + let(:wiki) { ProjectWiki.new(project, user) } + let(:gollum_wiki) { wiki.wiki } + + # Remove skip_gitaly_mock flag when gitaly_find_page when + # https://gitlab.com/gitlab-org/gitaly/merge_requests/539 gets merged + describe '#page', :skip_gitaly_mock do + it 'returns the right page' do + create_page('page1', 'content') + create_page('foo/page1', 'content') + + expect(gollum_wiki.page(title: 'page1', dir: '').url_path).to eq 'page1' + expect(gollum_wiki.page(title: 'page1', dir: 'foo').url_path).to eq 'foo/page1' + + destroy_page('page1') + destroy_page('page1', 'foo') + end + end + + def create_page(name, content) + gollum_wiki.write_page(name, :markdown, content, commit_details) + end + + def commit_details + Gitlab::Git::Wiki::CommitDetails.new(user.name, user.email, "test commit") + end + + def destroy_page(title, dir = '') + page = gollum_wiki.page(title: title, dir: dir) + wiki.delete_page(page, "test commit") + end +end diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 9840afe6c4e..4a1d12cd448 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -188,14 +188,37 @@ describe WikiPage do end end - describe "#update" do + describe '#create', :skip_gitaly_mock do + context 'with valid attributes' do + it 'raises an error if a page with the same path already exists' do + create_page('New Page', 'content') + create_page('foo/bar', 'content') + expect { create_page('New Page', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError + expect { create_page('foo/bar', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError + + destroy_page('New Page') + destroy_page('bar', 'foo') + end + + it 'if the title is preceded by a / it is removed' do + create_page('/New Page', 'content') + + expect(wiki.find_page('New Page')).not_to be_nil + + destroy_page('New Page') + end + end + end + + # Remove skip_gitaly_mock flag when gitaly_update_page implements moving pages + describe "#update", :skip_gitaly_mock do before do create_page("Update", "content") @page = wiki.find_page("Update") end after do - destroy_page(@page.title) + destroy_page(@page.title, @page.directory) end context "with valid attributes" do @@ -233,6 +256,95 @@ describe WikiPage do expect { @page.update(content: 'more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError) end end + + context 'when renaming a page' do + it 'raises an error if the page already exists' do + create_page('Existing Page', 'content') + + expect { @page.update(title: 'Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError) + expect(@page.title).to eq 'Update' + expect(@page.content).to eq 'new_content' + + destroy_page('Existing Page') + end + + it 'updates the content and rename the file' do + new_title = 'Renamed Page' + new_content = 'updated content' + + expect(@page.update(title: new_title, content: new_content)).to be_truthy + + @page = wiki.find_page(new_title) + + expect(@page).not_to be_nil + expect(@page.content).to eq new_content + end + end + + context 'when moving a page' do + it 'raises an error if the page already exists' do + create_page('foo/Existing Page', 'content') + + expect { @page.update(title: 'foo/Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError) + expect(@page.title).to eq 'Update' + expect(@page.content).to eq 'new_content' + + destroy_page('Existing Page', 'foo') + end + + it 'updates the content and moves the file' do + new_title = 'foo/Other Page' + new_content = 'new_content' + + expect(@page.update(title: new_title, content: new_content)).to be_truthy + + page = wiki.find_page(new_title) + + expect(page).not_to be_nil + expect(page.content).to eq new_content + end + + context 'in subdir' do + before do + create_page('foo/Existing Page', 'content') + @page = wiki.find_page('foo/Existing Page') + end + + it 'moves the page to the root folder if the title is preceded by /' do + expect(@page.slug).to eq 'foo/Existing-Page' + expect(@page.update(title: '/Existing Page', content: 'new_content')).to be_truthy + expect(@page.slug).to eq 'Existing-Page' + end + + it 'does nothing if it has the same title' do + original_path = @page.slug + + expect(@page.update(title: 'Existing Page', content: 'new_content')).to be_truthy + expect(@page.slug).to eq original_path + end + end + + context 'in root dir' do + it 'does nothing if the title is preceded by /' do + original_path = @page.slug + + expect(@page.update(title: '/Update', content: 'new_content')).to be_truthy + expect(@page.slug).to eq original_path + end + end + end + + context "with invalid attributes" do + it 'aborts update if title blank' do + expect(@page.update(title: '', content: 'new_content')).to be_falsey + expect(@page.content).to eq 'new_content' + + page = wiki.find_page('Update') + expect(page.content).to eq 'content' + + @page.title = 'Update' + end + end end describe "#destroy" do @@ -421,8 +533,8 @@ describe WikiPage do wiki.wiki.write_page(name, :markdown, content, commit_details) end - def destroy_page(title) - page = wiki.wiki.page(title: title) + def destroy_page(title, dir = '') + page = wiki.wiki.page(title: title, dir: dir) wiki.delete_page(page, "test commit") end |