summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-31 21:06:28 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-31 21:06:28 +0000
commit8f210aebe1d740e8ee194f171f1f33a6e1fba313 (patch)
treef43c545801bb96fd0737f18493fb30ab92972627
parent996f700997805b3590da8d8afdd19d193989078a (diff)
downloadgitlab-ce-8f210aebe1d740e8ee194f171f1f33a6e1fba313.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml1
-rw-r--r--.haml-lint_todo.yml2
-rw-r--r--.overcommit.yml.example17
-rw-r--r--app/assets/javascripts/pages/projects/wiki_directories/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/wiki_pages/index.js43
-rw-r--r--app/assets/javascripts/pages/projects/wikis/index.js34
-rw-r--r--app/assets/javascripts/pages/projects/wikis/wikis.js4
-rw-r--r--app/assets/stylesheets/framework/icons.scss15
-rw-r--r--app/assets/stylesheets/pages/wiki.scss41
-rw-r--r--app/controllers/concerns/preview_markdown.rb10
-rw-r--r--app/controllers/concerns/project_wiki_actions.rb41
-rw-r--r--app/controllers/projects/wiki_directories_controller.rb31
-rw-r--r--app/controllers/projects/wiki_pages_controller.rb180
-rw-r--r--app/controllers/projects/wikis_controller.rb191
-rw-r--r--app/helpers/application_settings_helper.rb1
-rw-r--r--app/helpers/icons_helper.rb6
-rw-r--r--app/helpers/wiki_helper.rb107
-rw-r--r--app/models/application_setting.rb5
-rw-r--r--app/models/application_setting_implementation.rb1
-rw-r--r--app/models/deployment.rb5
-rw-r--r--app/models/environment.rb1
-rw-r--r--app/models/project_wiki.rb42
-rw-r--r--app/models/wiki_directory.rb63
-rw-r--r--app/models/wiki_page.rb43
-rw-r--r--app/services/notes/create_service.rb15
-rw-r--r--app/views/admin/application_settings/_snowplow.html.haml3
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml6
-rw-r--r--app/views/projects/wiki_directories/_pages_wiki_directory.html.haml15
-rw-r--r--app/views/projects/wiki_directories/_sidebar_wiki_directory.html.haml7
-rw-r--r--app/views/projects/wiki_directories/_wiki_directory.html.haml1
-rw-r--r--app/views/projects/wiki_directories/empty.html.haml34
-rw-r--r--app/views/projects/wiki_directories/show.html.haml6
-rw-r--r--app/views/projects/wiki_pages/_page_title.html.haml4
-rw-r--r--app/views/projects/wiki_pages/_pages_wiki_page.html.haml8
-rw-r--r--app/views/projects/wiki_pages/_sidebar_wiki_page.html.haml11
-rw-r--r--app/views/projects/wiki_pages/_wiki_page.html.haml1
-rw-r--r--app/views/projects/wiki_pages/show.html.haml34
-rw-r--r--app/views/projects/wikis/_form.html.haml (renamed from app/views/projects/wiki_pages/_form.html.haml)10
-rw-r--r--app/views/projects/wikis/_main_links.html.haml (renamed from app/views/shared/wiki/_main_links.html.haml)2
-rw-r--r--app/views/projects/wikis/_pages_wiki_page.html.haml6
-rw-r--r--app/views/projects/wikis/_sidebar.html.haml (renamed from app/views/shared/wiki/_sidebar.html.haml)0
-rw-r--r--app/views/projects/wikis/_sidebar_wiki_page.html.haml3
-rw-r--r--app/views/projects/wikis/_wiki_directory.html.haml4
-rw-r--r--app/views/projects/wikis/_wiki_page.html.haml1
-rw-r--r--app/views/projects/wikis/edit.html.haml (renamed from app/views/projects/wiki_pages/edit.html.haml)14
-rw-r--r--app/views/projects/wikis/empty.html.haml (renamed from app/views/projects/wiki_pages/missing_page.html.haml)0
-rw-r--r--app/views/projects/wikis/history.html.haml (renamed from app/views/projects/wiki_pages/history.html.haml)8
-rw-r--r--app/views/projects/wikis/pages.html.haml32
-rw-r--r--app/views/projects/wikis/show.html.haml35
-rw-r--r--app/views/shared/empty_states/_wikis.html.haml9
-rw-r--r--app/views/shared/wiki/_page_listing.html.haml45
-rw-r--r--changelogs/unreleased/34230-fix-popover-image.yml5
-rw-r--r--changelogs/unreleased/add-snowplow-iglu-registry-application-setting.yml5
-rw-r--r--changelogs/unreleased/sort-wiki-pages-by-date.yml4
-rw-r--r--config/routes/project.rb2
-rw-r--r--config/routes/wiki.rb20
-rw-r--r--db/migrate/20191010174846_add_snowplow_iglu_registry_url_to_application_settings.rb9
-rw-r--r--db/migrate/20191024134020_add_index_to_zoom_meetings.rb17
-rw-r--r--db/schema.rb2
-rw-r--r--doc/api/settings.md1
-rw-r--r--lib/api/settings.rb1
-rw-r--r--lib/banzai/filter/wiki_link_filter/rewriter.rb2
-rw-r--r--lib/gitlab/tracking.rb3
-rw-r--r--lib/gitlab/usage_data.rb2
-rw-r--r--lib/gitlab/utils.rb10
-rw-r--r--locale/gitlab.pot45
-rw-r--r--qa/qa/page/project/wiki/edit.rb2
-rw-r--r--qa/qa/page/project/wiki/new.rb2
-rw-r--r--qa/qa/page/project/wiki/show.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb11
-rwxr-xr-xscripts/static-analysis38
-rw-r--r--spec/controllers/projects/wiki_directories_controller_spec.rb52
-rw-r--r--spec/controllers/projects/wiki_pages_controller_spec.rb399
-rw-r--r--spec/controllers/projects/wikis_controller_spec.rb239
-rw-r--r--spec/factories/wiki_pages.rb8
-rw-r--r--spec/features/projects/features_visibility_spec.rb102
-rw-r--r--spec/features/projects/wiki/markdown_preview_spec.rb170
-rw-r--r--spec/features/projects/wiki/user_creates_wiki_page_spec.rb219
-rw-r--r--spec/features/projects/wiki/user_deletes_wiki_page_spec.rb2
-rw-r--r--spec/features/projects/wiki/user_updates_wiki_page_spec.rb77
-rw-r--r--spec/features/projects/wiki/user_views_wiki_page_spec.rb31
-rw-r--r--spec/features/projects/wiki/user_views_wiki_pages_spec.rb172
-rw-r--r--spec/frontend/wikis_spec.js40
-rw-r--r--spec/helpers/wiki_helper_spec.rb21
-rw-r--r--spec/lib/banzai/filter/wiki_link_filter_spec.rb13
-rw-r--r--spec/lib/banzai/pipeline/wiki_pipeline_spec.rb209
-rw-r--r--spec/lib/gitlab/tracking_spec.rb4
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb10
-rw-r--r--spec/lib/gitlab/utils_spec.rb37
-rw-r--r--spec/models/application_setting_spec.rb4
-rw-r--r--spec/models/environment_spec.rb42
-rw-r--r--spec/models/project_wiki_spec.rb22
-rw-r--r--spec/models/wiki_directory_spec.rb187
-rw-r--r--spec/models/wiki_page_spec.rb91
-rw-r--r--spec/requests/api/settings_spec.rb3
-rw-r--r--spec/routing/project_routing_spec.rb42
-rw-r--r--spec/routing/wiki_routing_spec.rb103
-rw-r--r--spec/support/controllers/authorization_helpers.rb6
-rw-r--r--spec/support/helpers/capybara_helpers.rb10
-rw-r--r--spec/support/helpers/dropzone_helper.rb2
-rw-r--r--spec/support/helpers/git_helpers.rb5
-rw-r--r--spec/support/helpers/wiki_helpers.rb6
-rw-r--r--spec/support/matchers/issuable_matchers.rb3
-rw-r--r--spec/support/shared_examples/requests/api/discussions.rb23
-rw-r--r--spec/support/shared_examples/wiki_file_attachments_examples.rb8
106 files changed, 1403 insertions, 2346 deletions
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 5b1930faabb..acee30867d9 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -239,6 +239,7 @@ static-analysis:
dependencies: ["setup-test-env", "compile-assets pull-cache"]
variables:
SETUP_DB: "false"
+ parallel: 2
script:
- scripts/static-analysis
cache:
diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml
index a181d17d743..c6afe2c824c 100644
--- a/.haml-lint_todo.yml
+++ b/.haml-lint_todo.yml
@@ -343,6 +343,8 @@ linters:
- 'app/views/projects/triggers/_index.html.haml'
- 'app/views/projects/triggers/_trigger.html.haml'
- 'app/views/projects/triggers/edit.html.haml'
+ - 'app/views/projects/wikis/_new.html.haml'
+ - 'app/views/projects/wikis/_pages_wiki_page.html.haml'
- 'app/views/projects/wikis/edit.html.haml'
- 'app/views/projects/wikis/history.html.haml'
- 'app/views/repository_check_mailer/notify.html.haml'
diff --git a/.overcommit.yml.example b/.overcommit.yml.example
index 25823b9a8b3..9cd04825bc2 100644
--- a/.overcommit.yml.example
+++ b/.overcommit.yml.example
@@ -16,10 +16,25 @@
# Uncomment the following lines to make the configuration take effect.
PreCommit:
+ AuthorName:
+ enabled: false
+ EsLint:
+ enabled: true
+ # https://github.com/sds/overcommit/issues/338
+ command: './node_modules/eslint/bin/eslint.js'
+ HamlLint:
+ enabled: true
+ MergeConflicts:
+ enabled: true
+ exclude:
+ - '**/conflict/file_spec.rb'
+ - '**/git/conflict/parser_spec.rb'
+ # prettier? https://github.com/sds/overcommit/issues/614 https://github.com/sds/overcommit/issues/390#issuecomment-495703284
RuboCop:
enabled: true
# on_warn: fail # Treat all warnings as failures
-#
+ ScssLint:
+ enabled: true
#PostCheckout:
# ALL: # Special hook name that customizes all hooks of this type
# quiet: true # Change all post-checkout hooks to only display output on failure
diff --git a/app/assets/javascripts/pages/projects/wiki_directories/index.js b/app/assets/javascripts/pages/projects/wiki_directories/index.js
deleted file mode 100644
index b055b7cc322..00000000000
--- a/app/assets/javascripts/pages/projects/wiki_directories/index.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// currently, this controller inherits all behaviors from wikis
-import '../wikis/index';
diff --git a/app/assets/javascripts/pages/projects/wiki_pages/index.js b/app/assets/javascripts/pages/projects/wiki_pages/index.js
deleted file mode 100644
index 92549cb648c..00000000000
--- a/app/assets/javascripts/pages/projects/wiki_pages/index.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import $ from 'jquery';
-import Vue from 'vue';
-
-import Translate from '~/vue_shared/translate';
-import csrf from '~/lib/utils/csrf';
-import ShortcutsWiki from '~/behaviors/shortcuts/shortcuts_wiki';
-import ZenMode from '~/zen_mode';
-import GLForm from '~/gl_form';
-
-import deleteWikiModal from '../wikis/components/delete_wiki_modal.vue';
-import Wikis from '../wikis/wikis';
-
-document.addEventListener('DOMContentLoaded', () => {
- new Wikis(); // eslint-disable-line no-new
- new ShortcutsWiki(); // eslint-disable-line no-new
- new ZenMode(); // eslint-disable-line no-new
- new GLForm($('.wiki-form')); // eslint-disable-line no-new
-
- const deleteWikiModalWrapperEl = document.getElementById('delete-wiki-modal-wrapper');
-
- if (deleteWikiModalWrapperEl) {
- Vue.use(Translate);
-
- const { deleteWikiUrl, pageTitle } = deleteWikiModalWrapperEl.dataset;
-
- // eslint-disable-next-line no-new
- new Vue({
- el: deleteWikiModalWrapperEl,
- data: {
- deleteWikiUrl: '',
- },
- render(createElement) {
- return createElement(deleteWikiModal, {
- props: {
- pageTitle,
- deleteWikiUrl,
- csrfToken: csrf.token,
- },
- });
- },
- });
- }
-});
diff --git a/app/assets/javascripts/pages/projects/wikis/index.js b/app/assets/javascripts/pages/projects/wikis/index.js
index 1b0d8fb4b71..f5fd84d69ac 100644
--- a/app/assets/javascripts/pages/projects/wikis/index.js
+++ b/app/assets/javascripts/pages/projects/wikis/index.js
@@ -1,11 +1,41 @@
import $ from 'jquery';
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import csrf from '~/lib/utils/csrf';
import ShortcutsWiki from '~/behaviors/shortcuts/shortcuts_wiki';
-import GLForm from '~/gl_form';
-
import Wikis from './wikis';
+import ZenMode from '../../../zen_mode';
+import GLForm from '../../../gl_form';
+import deleteWikiModal from './components/delete_wiki_modal.vue';
document.addEventListener('DOMContentLoaded', () => {
new Wikis(); // eslint-disable-line no-new
new ShortcutsWiki(); // eslint-disable-line no-new
+ new ZenMode(); // eslint-disable-line no-new
new GLForm($('.wiki-form')); // eslint-disable-line no-new
+
+ const deleteWikiModalWrapperEl = document.getElementById('delete-wiki-modal-wrapper');
+
+ if (deleteWikiModalWrapperEl) {
+ Vue.use(Translate);
+
+ const { deleteWikiUrl, pageTitle } = deleteWikiModalWrapperEl.dataset;
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: deleteWikiModalWrapperEl,
+ data: {
+ deleteWikiUrl: '',
+ },
+ render(createElement) {
+ return createElement(deleteWikiModal, {
+ props: {
+ pageTitle,
+ deleteWikiUrl,
+ csrfToken: csrf.token,
+ },
+ });
+ },
+ });
+ }
});
diff --git a/app/assets/javascripts/pages/projects/wikis/wikis.js b/app/assets/javascripts/pages/projects/wikis/wikis.js
index 1bf799a5ee0..d41199f6374 100644
--- a/app/assets/javascripts/pages/projects/wikis/wikis.js
+++ b/app/assets/javascripts/pages/projects/wikis/wikis.js
@@ -12,8 +12,8 @@ export default class Wikis {
}
this.isNewWikiPage = Boolean(document.querySelector('.js-new-wiki-page'));
- this.editTitleInput = document.querySelector('form.wiki-form #wiki_page_title');
- this.commitMessageInput = document.querySelector('form.wiki-form #wiki_page_message');
+ this.editTitleInput = document.querySelector('form.wiki-form #wiki_title');
+ this.commitMessageInput = document.querySelector('form.wiki-form #wiki_message');
this.commitMessageI18n = this.isNewWikiPage
? s__('WikiPageCreate|Create %{pageTitle}')
: s__('WikiPageEdit|Update %{pageTitle}');
diff --git a/app/assets/stylesheets/framework/icons.scss b/app/assets/stylesheets/framework/icons.scss
index f73d1b41f84..a53f5d85949 100644
--- a/app/assets/stylesheets/framework/icons.scss
+++ b/app/assets/stylesheets/framework/icons.scss
@@ -99,18 +99,3 @@
justify-content: center;
color: $gray-700;
}
-
-.svg-icon {
- display: inline-flex;
- align-self: center;
-
- svg {
- height: 1em;
- width: 1em;
- }
-
- &.svg-baseline svg {
- top: 0.125em;
- position: relative;
- }
-}
diff --git a/app/assets/stylesheets/pages/wiki.scss b/app/assets/stylesheets/pages/wiki.scss
index 8f1b4cdb6d5..0b65b915abf 100644
--- a/app/assets/stylesheets/pages/wiki.scss
+++ b/app/assets/stylesheets/pages/wiki.scss
@@ -1,31 +1,3 @@
-.new-wiki-page {
- .new-wiki-page-slug-tip {
- display: inline-block;
- max-width: 100%;
- margin-top: 5px;
- }
-}
-
-.wiki-history,
-.wiki-page,
-.edit-wiki-page {
- margin-right: $gutter-width;
-}
-
-.edit-wiki-page {
- @media only screen and (min-width: map-get($grid-breakpoints, lg) + (2 * $gutter-width)) and (max-width: map-get($grid-breakpoints, lg) + (3 * $gutter-width)) {
- margin-right: $gutter-width * 1.5;
- }
-}
-
-.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;
@@ -33,15 +5,6 @@
padding-right: 7px;
}
-.container-fluid.wiki-page,
-.container-fluid.edit-wiki-page {
- width: initial;
-}
-
-.wiki-history.breadcrumbs {
- min-height: (2 * $gl-padding) + 22;
-}
-
.wiki-page-header {
position: relative;
@@ -116,7 +79,7 @@
}
.sidebar-container {
- padding-bottom: $gl-padding;
+ padding: $gl-padding 0;
width: calc(100% + 100px);
padding-right: 100px;
height: 100%;
@@ -162,7 +125,7 @@
}
.wiki-sidebar-header {
- padding: $gl-padding;
+ padding: 0 $gl-padding $gl-padding;
.gutter-toggle {
margin-top: 0;
diff --git a/app/controllers/concerns/preview_markdown.rb b/app/controllers/concerns/preview_markdown.rb
index 4189b8dcf96..1d84ddfba97 100644
--- a/app/controllers/concerns/preview_markdown.rb
+++ b/app/controllers/concerns/preview_markdown.rb
@@ -9,10 +9,11 @@ module PreviewMarkdown
markdown_params =
case controller_name
+ when 'wikis' then { pipeline: :wiki, project_wiki: @project_wiki, page_slug: params[:id] }
when 'snippets' then { skip_project_check: true }
when 'groups' then { group: group }
when 'projects' then projects_filter_params
- else preview_markdown_params
+ else {}
end
render json: {
@@ -24,7 +25,6 @@ module PreviewMarkdown
}
}
end
- # rubocop:enable Gitlab/ModuleWithInstanceVariables
private
@@ -35,12 +35,8 @@ module PreviewMarkdown
}
end
- # Override this method to customise the markdown for your controller
- def preview_markdown_params
- {}
- end
-
def markdown_service_params
params
end
+ # rubocop:enable Gitlab/ModuleWithInstanceVariables
end
diff --git a/app/controllers/concerns/project_wiki_actions.rb b/app/controllers/concerns/project_wiki_actions.rb
deleted file mode 100644
index 304e16a894a..00000000000
--- a/app/controllers/concerns/project_wiki_actions.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-# Controllers that include this concern must provide:
-# * project
-# * current_user
-module ProjectWikiActions
- extend ActiveSupport::Concern
-
- included do
- before_action :authorize_read_wiki!
- before_action :init_wiki_actions
-
- attr_accessor :project_wiki, :sidebar_page, :sidebar_wiki_entries
- end
-
- def init_wiki_actions
- load_project_wiki
- load_wiki_sidebar
- rescue ProjectWiki::CouldNotCreateWikiError
- flash[:notice] = _("Could not create Wiki Repository at this time. Please try again later.")
- redirect_to project_path(project)
- end
-
- def load_project_wiki
- self.project_wiki = load_wiki
- end
-
- def load_wiki_sidebar
- self.sidebar_page = project_wiki.find_sidebar(params[:version_id])
-
- return if sidebar_page.present?
-
- # Fallback to default sidebar
- self.sidebar_wiki_entries = WikiDirectory.group_by_directory(project_wiki.list_pages(limit: 15))
- end
-
- def load_wiki
- # Call #wiki to make sure the Wiki Repo is initialized
- ProjectWiki.new(project, current_user).tap(&:wiki)
- end
-end
diff --git a/app/controllers/projects/wiki_directories_controller.rb b/app/controllers/projects/wiki_directories_controller.rb
deleted file mode 100644
index f66da60f498..00000000000
--- a/app/controllers/projects/wiki_directories_controller.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-class Projects::WikiDirectoriesController < Projects::ApplicationController
- include ProjectWikiActions
-
- def self.local_prefixes
- [controller_path, 'shared/wiki']
- end
-
- def show
- @wiki_dir = find_dir || WikiDirectory.new(params[:id])
-
- return render('empty') if @wiki_dir.empty?
-
- @wiki_entries = @wiki_pages = Kaminari
- .paginate_array(@wiki_dir.pages)
- .page(params[:page])
-
- render 'show'
- end
-
- private
-
- def find_dir
- dir_params = params.permit(:id, :sort, :direction).dup.tap do |h|
- Gitlab::Utils.allow_hash_values(h, sort_params_config[:allowed])
- end
-
- project_wiki.find_dir(dir_params[:id], dir_params[:sort], dir_params[:direction])
- end
-end
diff --git a/app/controllers/projects/wiki_pages_controller.rb b/app/controllers/projects/wiki_pages_controller.rb
deleted file mode 100644
index 0ba397b08f8..00000000000
--- a/app/controllers/projects/wiki_pages_controller.rb
+++ /dev/null
@@ -1,180 +0,0 @@
-# frozen_string_literal: true
-
-class Projects::WikiPagesController < Projects::ApplicationController
- include ProjectWikiActions
- include SendsBlob
- include PreviewMarkdown
- include Gitlab::Utils::StrongMemoize
-
- def self.local_prefixes
- [controller_path, 'shared/wiki']
- end
-
- before_action :authorize_create_wiki!, only: [:edit, :create, :update]
- before_action :authorize_admin_wiki!, only: :destroy
-
- before_action :load_page, only: [:show, :edit, :update, :history, :destroy]
- before_action :valid_encoding?,
- if: -> { %w[show edit update].include?(action_name) && load_page }
- before_action only: [:edit, :update], unless: :valid_encoding? do
- redirect_to(project_wiki_path(@project, @page))
- end
-
- def new
- redirect_to project_wiki_path(@project, SecureRandom.uuid, random_title: true)
- end
-
- # `#show` handles a number of scenarios:
- #
- # - If `id` matches a WikiPage, then show the wiki page.
- # - If `id` is a file in the wiki repository, then send the file.
- # - If we know the user wants to create a new page with the given `id`,
- # then display a create form.
- # - Otherwise show the empty wiki page and invite the user to create a page.
- def show
- if @page
- show_page
- elsif file_blob
- show_blob
- elsif should_create_missing_page?
- create_missing_page
- else
- render 'missing_page'
- end
- end
-
- def edit
- end
-
- def update
- @page = WikiPages::UpdateService
- .new(@project, current_user, wiki_params)
- .execute(@page)
-
- return saved(:updated) if @page.valid?
-
- render 'edit'
- rescue WikiPage::PageChangedError, WikiPage::PageRenameError, Gitlab::Git::Wiki::OperationError => e
- @error = e
- render 'edit'
- end
-
- def create
- @page = WikiPages::CreateService
- .new(@project, current_user, wiki_params)
- .execute
-
- return saved(:created) if @page.persisted?
-
- render action: "edit"
- rescue Gitlab::Git::Wiki::OperationError => e
- @page = project_wiki.build_page(wiki_params)
- @error = e
-
- render 'edit'
- end
-
- def history
- if @page
- @page_versions = Kaminari.paginate_array(@page.versions(page: params[:page].to_i),
- total_count: @page.count_versions)
- .page(params[:page])
- else
- redirect_to(
- project_wiki_path(@project, :home),
- notice: _("Page not found")
- )
- end
- end
-
- def destroy
- WikiPages::DestroyService.new(@project, current_user).execute(@page)
-
- redirect_to project_wiki_path(@project, :home),
- status: 302,
- notice: _("Page was successfully deleted")
- rescue Gitlab::Git::Wiki::OperationError => e
- @error = e
- render 'edit'
- end
-
- private
-
- # Callback for PreviewMarkdown
- def preview_markdown_params
- { pipeline: :wiki, project_wiki: project_wiki, page_slug: params[:id] }
- end
-
- def show_page
- set_encoding_error unless valid_encoding?
-
- @page_dir = @project_wiki.find_dir(@page.directory) if @page.directory.present?
- @show_children = true
-
- render 'show'
- end
-
- def show_blob
- send_blob(@project_wiki.repository, file_blob)
- end
-
- def should_create_missing_page?
- view_param = @project_wiki.exists? ? 'create' : params[:view]
- view_param == 'create' && can?(current_user, :create_wiki, @project)
- end
-
- def create_missing_page
- # Assign a title to the WikiPage unless `id` is a randomly generated slug from #new
- title = params[:id] unless params[:random_title].present?
-
- @page = project_wiki.build_page(title: title)
-
- render 'edit'
- end
-
- def wiki_params
- params.require(:wiki_page).permit(:title, :content, :format, :message, :last_commit_sha)
- end
-
- def load_page
- @page ||= @project_wiki.find_page(*page_params)
- end
-
- def page_params
- keys = [:id]
- keys << :version_id if params[:action] == 'show'
-
- params.values_at(*keys)
- end
-
- def valid_encoding?
- strong_memoize(:valid_encoding) do
- @page.content.encoding == Encoding::UTF_8
- end
- end
-
- def set_encoding_error
- flash.now[:notice] = _("The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.")
- end
-
- def file_blob
- strong_memoize(:file_blob) do
- commit = @project_wiki.repository.commit(@project_wiki.default_branch)
-
- next unless commit
-
- @project_wiki.repository.blob_at(commit.id, params[:id])
- end
- end
-
- def saved(action)
- msg = case action
- when :updated
- _('Wiki was successfully updated')
- when :created
- _('Wiki was successfully created')
- end
-
- redirect_to(project_wiki_path(@project, @page), notice: msg)
- end
-end
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index d531d256721..b187fdb2723 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -1,28 +1,120 @@
# frozen_string_literal: true
class Projects::WikisController < Projects::ApplicationController
- include ProjectWikiActions
- include WikiHelper
+ include PreviewMarkdown
+ include SendsBlob
+ include Gitlab::Utils::StrongMemoize
- def self.local_prefixes
- [controller_path, 'shared/wiki']
+ before_action :authorize_read_wiki!
+ before_action :authorize_create_wiki!, only: [:edit, :create]
+ before_action :authorize_admin_wiki!, only: :destroy
+ before_action :load_project_wiki
+ before_action :load_page, only: [:show, :edit, :update, :history, :destroy]
+ before_action :valid_encoding?,
+ if: -> { %w[show edit update].include?(action_name) && load_page }
+ before_action only: [:edit, :update], unless: :valid_encoding? do
+ redirect_to(project_wiki_path(@project, @page))
+ end
+
+ def new
+ redirect_to project_wiki_path(@project, SecureRandom.uuid, random_title: true)
end
def pages
- @nesting = show_children_param
- @show_children = @nesting != ProjectWiki::NESTING_CLOSED
@wiki_pages = Kaminari.paginate_array(
- project_wiki.list_pages(**sort_params)
+ @project_wiki.list_pages(sort: params[:sort], direction: params[:direction])
).page(params[:page])
- @wiki_entries = case @nesting
- when ProjectWiki::NESTING_FLAT
- @wiki_pages
- else
- WikiDirectory.group_by_directory(@wiki_pages)
- end
+ @wiki_entries = WikiPage.group_by_directory(@wiki_pages)
+ end
+
+ # `#show` handles a number of scenarios:
+ #
+ # - If `id` matches a WikiPage, then show the wiki page.
+ # - If `id` is a file in the wiki repository, then send the file.
+ # - If we know the user wants to create a new page with the given `id`,
+ # then display a create form.
+ # - Otherwise show the empty wiki page and invite the user to create a page.
+ def show
+ if @page
+ set_encoding_error unless valid_encoding?
+
+ render 'show'
+ elsif file_blob
+ send_blob(@project_wiki.repository, file_blob)
+ elsif show_create_form?
+ # Assign a title to the WikiPage unless `id` is a randomly generated slug from #new
+ title = params[:id] unless params[:random_title].present?
+
+ @page = build_page(title: title)
+
+ render 'edit'
+ else
+ render 'empty'
+ end
+ end
+
+ def edit
+ end
+
+ def update
+ return render('empty') unless can?(current_user, :create_wiki, @project)
+
+ @page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page)
+
+ if @page.valid?
+ redirect_to(
+ project_wiki_path(@project, @page),
+ notice: _('Wiki was successfully updated.')
+ )
+ else
+ render 'edit'
+ end
+ rescue WikiPage::PageChangedError, WikiPage::PageRenameError, Gitlab::Git::Wiki::OperationError => e
+ @error = e
+ render 'edit'
+ end
+
+ def create
+ @page = WikiPages::CreateService.new(@project, current_user, wiki_params).execute
+
+ if @page.persisted?
+ redirect_to(
+ project_wiki_path(@project, @page),
+ notice: _('Wiki was successfully updated.')
+ )
+ else
+ render action: "edit"
+ end
+ rescue Gitlab::Git::Wiki::OperationError => e
+ @page = build_page(wiki_params)
+ @error = e
+
+ render 'edit'
+ end
+
+ def history
+ if @page
+ @page_versions = Kaminari.paginate_array(@page.versions(page: params[:page].to_i),
+ total_count: @page.count_versions)
+ .page(params[:page])
+ else
+ redirect_to(
+ project_wiki_path(@project, :home),
+ notice: _("Page not found")
+ )
+ end
+ end
+
+ def destroy
+ WikiPages::DestroyService.new(@project, current_user).execute(@page)
- render 'show'
+ redirect_to project_wiki_path(@project, :home),
+ status: 302,
+ notice: _("Page was successfully deleted")
+ rescue Gitlab::Git::Wiki::OperationError => e
+ @error = e
+ render 'edit'
end
def git_access
@@ -30,13 +122,74 @@ class Projects::WikisController < Projects::ApplicationController
private
- def sort_params
- process_params(sort_params_config)
+ def show_create_form?
+ can?(current_user, :create_wiki, @project) &&
+ @page.nil? &&
+ # Always show the create form when the wiki has had at least one page created.
+ # Otherwise, we only show the form when the user has navigated from
+ # the 'empty wiki' page
+ (@project_wiki.exists? || params[:view] == 'create')
end
- def show_children_param
- config = nesting_params_config(params[:sort])
+ def load_project_wiki
+ @project_wiki = load_wiki
+
+ # Call #wiki to make sure the Wiki Repo is initialized
+ @project_wiki.wiki
+
+ @sidebar_page = @project_wiki.find_sidebar(params[:version_id])
+
+ unless @sidebar_page # Fallback to default sidebar
+ @sidebar_wiki_entries = WikiPage.group_by_directory(@project_wiki.list_pages(limit: 15))
+ end
+ rescue ProjectWiki::CouldNotCreateWikiError
+ flash[:notice] = _("Could not create Wiki Repository at this time. Please try again later.")
+ redirect_to project_path(@project)
+ false
+ end
+
+ def load_wiki
+ ProjectWiki.new(@project, current_user)
+ end
+
+ def wiki_params
+ params.require(:wiki).permit(:title, :content, :format, :message, :last_commit_sha)
+ end
+
+ def build_page(args = {})
+ WikiPage.new(@project_wiki).tap do |page|
+ page.update_attributes(args) # rubocop:disable Rails/ActiveRecordAliases
+ end
+ end
+
+ def load_page
+ @page ||= @project_wiki.find_page(*page_params)
+ end
+
+ def page_params
+ keys = [:id]
+ keys << :version_id if params[:action] == 'show'
+
+ params.values_at(*keys)
+ end
+
+ def valid_encoding?
+ strong_memoize(:valid_encoding) do
+ @page.content.encoding == Encoding::UTF_8
+ end
+ end
+
+ def set_encoding_error
+ flash.now[:notice] = _("The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.")
+ end
+
+ def file_blob
+ strong_memoize(:file_blob) do
+ commit = @project_wiki.repository.commit(@project_wiki.default_branch)
+
+ next unless commit
- process_params(config)
+ @project_wiki.repository.blob_at(commit.id, params[:id])
+ end
end
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 7b5a1a02b98..f90ad0c300c 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -290,6 +290,7 @@ module ApplicationSettingsHelper
:snowplow_cookie_domain,
:snowplow_enabled,
:snowplow_site_id,
+ :snowplow_iglu_registry_url,
:push_event_hooks_limit,
:push_event_activities_limit,
:custom_http_clone_url_root,
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index 66b88f6b626..4f73270577f 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -41,12 +41,6 @@ module IconsHelper
ActionController::Base.helpers.image_path('file_icons.svg', host: sprite_base_url)
end
- def sprite_icon_with_text(icon_name, content, opts = {})
- wrapper_class = opts.delete(:wrapper_class)
- icon = sprite_icon(icon_name, opts)
- content_tag(:span, [icon, content].join('').html_safe, class: wrapper_class)
- end
-
def sprite_icon(icon_name, size: nil, css_class: nil)
if Gitlab::Sentry.should_raise_for_dev?
unless known_sprites.include?(icon_name)
diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb
index 3cf610cbd38..dd8fde2a697 100644
--- a/app/helpers/wiki_helper.rb
+++ b/app/helpers/wiki_helper.rb
@@ -48,23 +48,14 @@ module WikiHelper
expose_url(api_v4_projects_wikis_attachments_path(id: @project.id))
end
- WIKI_SORT_CSS_CLASSES = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort'
-
- def wiki_sort_controls(sort_params = {}, &block)
- current_sort = sort_params[:sort] || ProjectWiki::TITLE_ORDER
- current_direction = (sort_params[:direction] || 'asc').inquiry
-
- reversed_direction = current_direction.desc? ? 'asc' : 'desc'
- icon_class = current_direction.desc? ? 'highest' : 'lowest'
-
- sorting = sort_params.merge(sort: current_sort, direction: reversed_direction)
- opts = {
- type: 'button',
- class: WIKI_SORT_CSS_CLASSES,
- title: _('Sort direction')
- }
-
- link_to(yield(sorting), opts) do
+ def wiki_sort_controls(project, sort, direction)
+ sort ||= ProjectWiki::TITLE_ORDER
+ link_class = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort'
+ reversed_direction = direction == 'desc' ? 'asc' : 'desc'
+ icon_class = direction == 'desc' ? 'highest' : 'lowest'
+
+ link_to(project_wikis_pages_path(project, sort: sort, direction: reversed_direction),
+ type: 'button', class: link_class, title: _('Sort direction')) do
sprite_icon("sort-#{icon_class}", size: 16)
end
end
@@ -76,86 +67,4 @@ module WikiHelper
s_("Wiki|Title")
end
end
-
- # Render the sprite icon given the current show_children state
- def wiki_show_children_icon(nesting)
- icon_name, icon_text =
- case nesting
- when ProjectWiki::NESTING_TREE
- ['folder-open', s_("Wiki|Show folder contents")]
- when ProjectWiki::NESTING_CLOSED
- ['folder-o', s_("Wiki|Hide folder contents")]
- else
- ['list-bulleted', s_("Wiki|Show files separately")]
- end
-
- sprite_icon_with_text(icon_name, icon_text, size: 16)
- end
-
- def wiki_page_link(wiki_page, nesting, project)
- link = link_to(wiki_page.title,
- project_wiki_path(project, wiki_page),
- class: 'wiki-page-title')
-
- case nesting
- when ProjectWiki::NESTING_FLAT
- tags = []
- if wiki_page.directory.present?
- wiki_dir = WikiDirectory.new(wiki_page.directory)
- tags << link_to(wiki_dir.slug, project_wiki_dir_path(project, wiki_dir), class: 'wiki-page-dir-name')
- tags << content_tag(:span, '/', class: 'wiki-page-name-separator')
- end
-
- tags << link
- tags.join.html_safe
- else
- link
- end
- end
-
- def sort_params_config
- {
- keys: [:sort, :direction],
- defaults: {
- sort: ProjectWiki::TITLE_ORDER, direction: ProjectWiki::DIRECTION_ASC
- },
- allowed: {
- sort: ProjectWiki::SORT_ORDERS, direction: ProjectWiki::SORT_DIRECTIONS
- }
- }
- end
-
- def nesting_params_config(sort_key)
- default_val = case sort_key
- when ProjectWiki::CREATED_AT_ORDER
- ProjectWiki::NESTING_FLAT
- else
- ProjectWiki::NESTING_CLOSED
- end
- {
- keys: [:show_children],
- defaults: { show_children: default_val },
- allowed: { show_children: ProjectWiki::NESTINGS }
- }
- end
-
- def process_params(config)
- unprocessed = params.permit(*config[:keys])
-
- processed = unprocessed
- .with_defaults(config[:defaults])
- .tap { |h| Gitlab::Utils.allow_hash_values(h, config[:allowed]) }
- .to_hash
- .transform_keys(&:to_sym)
-
- if processed.keys == config[:keys]
- processed.size == 1 ? processed.values.first : processed
- else
- raise ActionController::BadRequest, "illegal parameters: #{unprocessed}"
- end
- end
-
- def home_page?
- params[:id] == 'home'
- end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 4ecc9bc2153..cfae79ec016 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -104,6 +104,11 @@ class ApplicationSetting < ApplicationRecord
hostname: true,
if: :snowplow_enabled
+ validates :snowplow_iglu_registry_url,
+ addressable_url: true,
+ allow_blank: true,
+ if: :snowplow_enabled
+
validates :pendo_url,
presence: true,
public_url: true,
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 0312183d11f..6cc77cca8a3 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -129,6 +129,7 @@ module ApplicationSettingImplementation
snowplow_cookie_domain: nil,
snowplow_enabled: false,
snowplow_site_id: nil,
+ snowplow_iglu_registry_url: nil,
custom_http_clone_url_root: nil,
pendo_enabled: false,
pendo_url: nil
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index 7ccd5e98360..698988e9295 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -75,6 +75,11 @@ class Deployment < ApplicationRecord
find(ids)
end
+ def self.distinct_on_environment
+ order('environment_id, deployments.id DESC')
+ .select('DISTINCT ON (environment_id) deployments.*')
+ end
+
def self.find_successful_deployment!(iid)
success.find_by!(iid: iid)
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index b426941d8af..602dce89c4a 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -10,6 +10,7 @@ class Environment < ApplicationRecord
has_many :successful_deployments, -> { success }, class_name: 'Deployment'
has_one :last_deployment, -> { success.order('deployments.id DESC') }, class_name: 'Deployment'
+ has_one :last_visible_deployment, -> { visible.distinct_on_environment }, class_name: 'Deployment'
before_validation :nullify_external_url
before_validation :generate_slug, if: ->(env) { env.slug.blank? }
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index e0fcebf2642..bb222ac7629 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -17,13 +17,6 @@ class ProjectWiki
CREATED_AT_ORDER = 'created_at'
DIRECTION_DESC = 'desc'
DIRECTION_ASC = 'asc'
- SORT_ORDERS = [TITLE_ORDER, CREATED_AT_ORDER].freeze
- SORT_DIRECTIONS = [DIRECTION_ASC, DIRECTION_DESC].freeze
-
- NESTING_FLAT = 'flat'
- NESTING_TREE = 'tree'
- NESTING_CLOSED = 'hidden'
- NESTINGS = [NESTING_TREE, NESTING_CLOSED, NESTING_FLAT].freeze
# Returns a string describing what went wrong after
# an operation fails.
@@ -65,11 +58,7 @@ class ProjectWiki
end
def wiki_base_path
- ::File.join(project_base_path, 'wikis')
- end
-
- def wiki_page_path
- ::File.join(project_base_path, '-', 'wiki_pages')
+ [Gitlab.config.gitlab.relative_url_root, '/', @project.full_path, '/wikis'].join('')
end
# Returns the Gitlab::Git::Wiki object.
@@ -136,23 +125,6 @@ class ProjectWiki
end
end
- # Finds directory within the repository based on a slug
- #
- # dir_name - The directory prefix.
- #
- # Returns an initialized WikiDirectory instance or nil
- def find_dir(dir_name, sort = nil, direction = DIRECTION_ASC)
- descending = direction == DIRECTION_DESC
- # WikiListPagesRequest currently does not support server-side
- # filtering. Ideally this logic should be moved to the gitaly
- # side.
- pages = wiki
- .list_pages(sort: sort, direction_desc: descending)
- .map { |page| WikiPage.new(self, page, true) }
- .select { |wp| wp.directory == dir_name }
- WikiDirectory.new(dir_name, pages) if pages.present?
- end
-
def find_sidebar(version = nil)
find_page(SIDEBAR, version)
end
@@ -172,12 +144,6 @@ class ProjectWiki
false
end
- def build_page(attrs)
- WikiPage.new(self).tap do |page|
- page.update_attributes(attrs) # rubocop:disable Rails/ActiveRecordAliases
- end
- end
-
def update_page(page, content:, title: nil, format: :markdown, message: nil)
commit = commit_details(:updated, message, page.title)
@@ -205,7 +171,7 @@ class ProjectWiki
title_array = title.split("/")
title = title_array.pop
- [title, ::File.join(title_array)]
+ [title, title_array.join("/")]
end
def repository
@@ -232,10 +198,6 @@ class ProjectWiki
private
- def project_base_path
- ::File.join(Gitlab.config.gitlab.relative_url_root, @project.full_path)
- end
-
def create_repo!(raw_repository)
gitlab_shell.create_wiki_repository(project)
diff --git a/app/models/wiki_directory.rb b/app/models/wiki_directory.rb
index 6c86c11e7fb..712ba79bbd2 100644
--- a/app/models/wiki_directory.rb
+++ b/app/models/wiki_directory.rb
@@ -1,75 +1,20 @@
# frozen_string_literal: true
class WikiDirectory
- include StaticModel
include ActiveModel::Validations
attr_accessor :slug, :pages
validates :slug, presence: true
- # StaticModel overrides and configuration:
-
- def self.primary_key
- 'slug'
- end
-
- def id
- "#{slug}@#{last_version&.sha}"
- end
-
- def self.model_name
- ActiveModel::Name.new(self, nil, 'wiki_dir')
- end
-
- alias_method :to_param, :slug
- alias_method :title, :slug
-
- # Sorts and groups pages by directory.
- #
- # pages - an array of WikiPage objects.
- #
- # Returns an array of WikiPage and WikiDirectory objects.
- # The entries are sorted in the order of the input array, where
- # directories appear in the position of their first member.
- def self.group_by_directory(pages)
- grouped = []
- dirs = Hash.new do |h, k|
- new(k).tap { |dir| grouped << (h[k] = dir) }
- end
-
- Array.wrap(pages).each_with_object(grouped) do |page, top_level|
- group = page.directory.present? ? dirs[page.directory] : top_level
-
- group << page
- end
- end
-
def initialize(slug, pages = [])
@slug = slug
@pages = pages
end
- def <<(page)
- @pages << page
- @last_version = nil
- end
-
- def last_version
- @last_version ||= @pages.map(&:last_version).max_by(&:authored_date)
- end
-
- def page_count
- @pages.size
- end
-
- def empty?
- page_count.zero?
- end
-
- def to_partial_path(context = nil)
- name = [context, 'wiki_directory'].compact.join('_')
-
- "projects/wiki_directories/#{name}"
+ # Relative path to the partial to be used when rendering collections
+ # of this object.
+ def to_partial_path
+ 'projects/wikis/wiki_directory'
end
end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index 3006753e9e7..68241d2bd95 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -15,7 +15,30 @@ class WikiPage
end
def self.model_name
- ActiveModel::Name.new(self, nil, 'wiki_page')
+ ActiveModel::Name.new(self, nil, 'wiki')
+ end
+
+ # Sorts and groups pages by directory.
+ #
+ # pages - an array of WikiPage objects.
+ #
+ # Returns an array of WikiPage and WikiDirectory objects. The entries are
+ # sorted by alphabetical order (directories and pages inside each directory).
+ # Pages at the root level come before everything.
+ def self.group_by_directory(pages)
+ return [] if pages.blank?
+
+ pages.each_with_object([]) do |page, grouped_pages|
+ next grouped_pages << page unless page.directory.present?
+
+ directory = grouped_pages.find do |obj|
+ obj.is_a?(WikiDirectory) && obj.slug == page.directory
+ end
+
+ next directory.pages << page if directory
+
+ grouped_pages << WikiDirectory.new(page.directory, [page])
+ end
end
def self.unhyphenize(name)
@@ -43,16 +66,6 @@ class WikiPage
Gitlab::HookData::WikiPageBuilder.new(self).build
end
- # Create a new WikiPage
- #
- # == Parameters:
- # wiki::
- # A `ProjectWiki` model object
- # page::
- # A `Gitlab::Git::WikiPage` business object, to which this class provides a facade
- # persisted::
- # Is this page fully saved on disk?
- #
def initialize(wiki, page = nil, persisted = false)
@wiki = wiki
@page = page
@@ -243,10 +256,10 @@ class WikiPage
end
end
- def to_partial_path(context = nil)
- name = [context, 'wiki_page'].compact.join('_')
-
- "projects/wiki_pages/#{name}"
+ # Relative path to the partial to be used when rendering collections
+ # of this object.
+ def to_partial_path
+ 'projects/wikis/wiki_page'
end
def id
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index c136803ef3b..9e6cbfa06fe 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -42,6 +42,10 @@ module Notes
clear_noteable_diffs_cache(note)
Suggestions::CreateService.new(note).execute
increment_usage_counter(note)
+
+ if Feature.enabled?(:notes_create_service_tracking, project)
+ Gitlab::Tracking.event('Notes::CreateService', 'execute', tracking_data_for(note))
+ end
end
if quick_actions_service.commands_executed_count.to_i > 0
@@ -59,5 +63,16 @@ module Notes
note
end
+
+ private
+
+ def tracking_data_for(note)
+ label = Gitlab.ee? && note.author == User.visual_review_bot ? 'anonymous_visual_review_note' : 'note'
+
+ {
+ label: label,
+ value: note.id
+ }
+ end
end
end
diff --git a/app/views/admin/application_settings/_snowplow.html.haml b/app/views/admin/application_settings/_snowplow.html.haml
index 31fd12d191e..dd454ce5dd7 100644
--- a/app/views/admin/application_settings/_snowplow.html.haml
+++ b/app/views/admin/application_settings/_snowplow.html.haml
@@ -26,5 +26,8 @@
.form-group
= f.label :snowplow_cookie_domain, _('Cookie domain'), class: 'label-light'
= f.text_field :snowplow_cookie_domain, class: 'form-control'
+ .form-group
+ = f.label :snowplow_iglu_registry_url, _('Iglu registry URL (optional)'), class: 'label-light'
+ = f.text_field :snowplow_iglu_registry_url, class: 'form-control'
= f.submit _('Save changes'), class: 'btn btn-success'
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index fdad2a64a80..2c0cb973542 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -264,7 +264,7 @@
dismiss_endpoint: user_callouts_path } }
- if show_cluster_hint
.feature-highlight-popover-content
- = image_tag 'illustrations/cluster_popover.svg', class: 'feature-highlight-illustration'
+ = image_tag 'illustrations/cluster_popover.svg', class: 'feature-highlight-illustration', lazy: false, alt: _('Kubernetes popover')
.feature-highlight-popover-sub-content
%p= _('Allows you to add and manage Kubernetes clusters.')
%p
@@ -282,14 +282,14 @@
- if project_nav_tab? :wiki
- wiki_url = project_wiki_path(@project, :home)
- = nav_link(controller: [:wikis, :wiki_pages, :wiki_directories]) do
+ = nav_link(controller: :wikis) do
= link_to wiki_url, class: 'shortcuts-wiki', data: { qa_selector: 'wiki_link' } do
.nav-icon-container
= sprite_icon('book')
%span.nav-item-name
= _('Wiki')
%ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: [:wikis, :wiki_pages, :wiki_directories], html_options: { class: "fly-out-top-item" } ) do
+ = nav_link(controller: :wikis, html_options: { class: "fly-out-top-item" } ) do
= link_to wiki_url do
%strong.fly-out-top-item-name
= _('Wiki')
diff --git a/app/views/projects/wiki_directories/_pages_wiki_directory.html.haml b/app/views/projects/wiki_directories/_pages_wiki_directory.html.haml
deleted file mode 100644
index a9d2f38da88..00000000000
--- a/app/views/projects/wiki_directories/_pages_wiki_directory.html.haml
+++ /dev/null
@@ -1,15 +0,0 @@
-%li
- %span.text-secondary-500.svg-icon.svg-baseline
- - if @show_children
- = sprite_icon('folder-open', size: 16)
- - else
- = sprite_icon('folder-o', size: 16)
-
- = link_to wiki_dir.slug, project_wiki_dir_path(@project, wiki_dir)
- - unless @show_children
- %span.badge.badge-pill.wiki-dir-page-count= wiki_dir.page_count
- .float-right
- %small= (s_("Last edited %{date}") % { date: time_ago_with_tooltip(wiki_dir.last_version.authored_date) }).html_safe
- - if @show_children
- %ul
- = render wiki_dir.pages, context: context
diff --git a/app/views/projects/wiki_directories/_sidebar_wiki_directory.html.haml b/app/views/projects/wiki_directories/_sidebar_wiki_directory.html.haml
deleted file mode 100644
index 2f62e9d4516..00000000000
--- a/app/views/projects/wiki_directories/_sidebar_wiki_directory.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-%li
- %span.text-secondary-300.svg-icon.svg-baseline
- = sprite_icon('folder-open', size: 16)
-
- = link_to wiki_dir.slug, project_wiki_dir_path(@project, wiki_dir)
- %ul= render wiki_dir.pages, context: context
-
diff --git a/app/views/projects/wiki_directories/_wiki_directory.html.haml b/app/views/projects/wiki_directories/_wiki_directory.html.haml
deleted file mode 100644
index 022c209c5bd..00000000000
--- a/app/views/projects/wiki_directories/_wiki_directory.html.haml
+++ /dev/null
@@ -1 +0,0 @@
-= render wiki_directory.to_partial_path(context), wiki_dir: wiki_directory, context: context
diff --git a/app/views/projects/wiki_directories/empty.html.haml b/app/views/projects/wiki_directories/empty.html.haml
deleted file mode 100644
index cab1c3acb60..00000000000
--- a/app/views/projects/wiki_directories/empty.html.haml
+++ /dev/null
@@ -1,34 +0,0 @@
-- layout_path = 'shared/empty_states/wikis_layout'
-- add_to_breadcrumbs _("Wiki"), project_wiki_path(@project, :home)
-- add_to_breadcrumbs s_("Wiki|Pages"), project_wikis_pages_path(@project)
-- breadcrumb_title s_(@wiki_dir.slug)
-- page_title @wiki_dir.slug
-
-- if can?(current_user, :create_wiki, @project)
- - create_path = project_wiki_path(@project, params[:id], { view: 'create', params: { title: "#{params[:id]}/" } })
- - create_link = link_to s_('WikiDirEmpty|Create a page in this directory'), create_path, class: 'btn btn-success qa-create-first-page-link', title: s_('WikiDirEmpty|Create a page')
-
- = render layout: layout_path, locals: { image_path: 'illustrations/wiki_login_empty.svg' } do
- %h4.text-left
- = s_('WikiDirEmpty|This directory has no wiki pages')
- %p.text-left
- = s_("WikiDirEmpty|A wiki is where you can store all the details about your project. This can include why you've created it, its principles, how to use it, and so on.")
- = create_link
-
-- elsif can?(current_user, :read_issue, @project)
- - issues_link = link_to s_('WikiEmptyIssueMessage|issue tracker'), project_issues_path(@project)
- - new_issue_link = link_to s_('WikiEmpty|Suggest wiki improvement'), new_project_issue_path(@project), class: 'btn btn-success', title: s_('WikiEmptyIssueMessage|Suggest wiki improvement')
-
- = render layout: layout_path, locals: { image_path: 'illustrations/wiki_logout_empty.svg' } do
- %h4
- = s_('WikiDirEmpty|This directory has no wiki pages')
- %p.text-left
- = s_('WikiEmptyIssueMessage|You must be a project member in order to add wiki pages. If you have suggestions for how to improve the wiki for this project, consider opening an issue in the %{issues_link}.').html_safe % { issues_link: issues_link }
- = new_issue_link
-
-- else
- = render layout: layout_path, locals: { image_path: 'illustrations/wiki_logout_empty.svg' } do
- %h4
- = s_('WikiDirEmpty|This directory has no wiki pages')
- %p
- = s_('WikiEmpty|You must be a project member in order to add wiki pages.')
diff --git a/app/views/projects/wiki_directories/show.html.haml b/app/views/projects/wiki_directories/show.html.haml
deleted file mode 100644
index 4c7978d1216..00000000000
--- a/app/views/projects/wiki_directories/show.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- add_to_breadcrumbs _("Wiki"), project_wiki_path(@project, :home)
-- add_to_breadcrumbs s_("Wiki|Pages"), project_wikis_pages_path(@project)
-- breadcrumb_title s_(@wiki_dir.slug)
-- page_title @wiki_dir.slug
-
-= render 'page_listing', { allow_change_nesting: false, wiki_page_title: page_title, page_path: ->(opts) { project_wiki_dir_path(@project, @wiki_dir, opts) } }
diff --git a/app/views/projects/wiki_pages/_page_title.html.haml b/app/views/projects/wiki_pages/_page_title.html.haml
deleted file mode 100644
index a3b077999e6..00000000000
--- a/app/views/projects/wiki_pages/_page_title.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-= link_to @page.human_title, project_wiki_path(@project, @page)
-%span.light
- = _('&middot;').html_safe
- = subtitle
diff --git a/app/views/projects/wiki_pages/_pages_wiki_page.html.haml b/app/views/projects/wiki_pages/_pages_wiki_page.html.haml
deleted file mode 100644
index c177d03bee1..00000000000
--- a/app/views/projects/wiki_pages/_pages_wiki_page.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-%li
- %span.text-secondary-500.svg-icon.svg-baseline= sprite_icon('book', size: 16)
- = wiki_page_link(wiki_page, @nesting, @project)
- .float-right
- %span.badge.badge-pill.wiki-page-format= _(wiki_page.format)
- - if wiki_page.last_version
- = '/'
- %small= (s_("Last edited %{date}") % { date: time_ago_with_tooltip(wiki_page.last_version.authored_date) }).html_safe
diff --git a/app/views/projects/wiki_pages/_sidebar_wiki_page.html.haml b/app/views/projects/wiki_pages/_sidebar_wiki_page.html.haml
deleted file mode 100644
index 205c3dd76bf..00000000000
--- a/app/views/projects/wiki_pages/_sidebar_wiki_page.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-- is_active = params[:id] == wiki_page.slug
-- icon_active_class = is_active ? 'text-secondary-800' : 'text-secondary-300'
-
-%li{ class: active_when(is_active) }
- %span.svg-icon.svg-baseline{ class: icon_active_class }
- = sprite_icon('book', size: 16)
- - if is_active
- = wiki_page.human_title
- - else
- = link_to project_wiki_path(@project, wiki_page) do
- = wiki_page.human_title
diff --git a/app/views/projects/wiki_pages/_wiki_page.html.haml b/app/views/projects/wiki_pages/_wiki_page.html.haml
deleted file mode 100644
index 947e96fed6b..00000000000
--- a/app/views/projects/wiki_pages/_wiki_page.html.haml
+++ /dev/null
@@ -1 +0,0 @@
-= render wiki_page.to_partial_path(context), wiki_page: wiki_page
diff --git a/app/views/projects/wiki_pages/show.html.haml b/app/views/projects/wiki_pages/show.html.haml
deleted file mode 100644
index 879ddfb03c8..00000000000
--- a/app/views/projects/wiki_pages/show.html.haml
+++ /dev/null
@@ -1,34 +0,0 @@
-- @content_class = 'wiki-page' + (fluid_layout ? '' : ' limit-container-width')
-- breadcrumb_title @page.human_title
-- page_title @page.human_title, _("Wiki")
-- add_to_breadcrumbs _("Wiki"), project_wiki_path(@project, :home)
-- add_to_breadcrumbs s_("Wiki|Pages"), project_wikis_pages_path(@project)
-- if @page_dir.present?
- - add_to_breadcrumbs _(@page_dir.slug), project_wiki_dir_path(@project, @page_dir)
-
-.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row
- %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
- = icon('angle-double-left')
-
- .nav-text.flex-fill
- %h2.wiki-page-title= @page.human_title
- %span.wiki-last-edit-by
- - if @page.last_version
- = (_("Last edited by %{name}") % { name: "<strong>#{@page.last_version.author_name}</strong>" }).html_safe
- #{time_ago_with_tooltip(@page.last_version.authored_date)}
-
- .nav-controls.pb-md-3.pb-lg-0
- = render 'main_links'
-
-- if @page.historical?
- .warning_message
- = s_("WikiHistoricalPage|This is an old version of this page.")
- - most_recent_link = link_to s_("WikiHistoricalPage|most recent version"), project_wiki_path(@project, @page)
- - history_link = link_to s_("WikiHistoricalPage|history"), project_wiki_history_path(@project, @page)
- = (s_("WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}.") % { most_recent_link: most_recent_link, history_link: history_link }).html_safe
-
-.prepend-top-default.append-bottom-default
- .md.md-file.qa-wiki-page-content
- = render_wiki_content(@page)
-
-= render 'sidebar'
diff --git a/app/views/projects/wiki_pages/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index 8f5757d6d98..a153f527ee0 100644
--- a/app/views/projects/wiki_pages/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -1,11 +1,9 @@
- form_classes = 'wiki-form common-note-form prepend-top-default js-quick-submit'
- form_classes += ' js-new-wiki-page' unless @page.persisted?
-= form_for [@project.namespace.becomes(Namespace), @project, @page],
- method: @page.persisted? ? 'put' : 'post',
- url: { controller: 'wiki_pages', action: @page.persisted? ? :update : :create },
- html: { class: form_classes },
- data: { uploads_path: uploads_path } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post,
+ html: { class: form_classes },
+ data: { uploads_path: uploads_path } do |f|
= form_errors(@page)
- if @page.persisted?
@@ -14,7 +12,7 @@
.form-group.row
.col-sm-12= f.label :title, class: 'control-label-full-width'
.col-sm-12
- = f.text_field :title, class: 'form-control qa-wiki-title-textbox', value: @page.title, required: true, autofocus: !@page.persisted?, placeholder: s_('Wiki|Page title')
+ = f.text_field :title, class: 'form-control qa-wiki-title-textbox', value: @page.title, required: true, autofocus: !@page.persisted?, placeholder: _('Wiki|Page title')
%span.d-inline-block.mw-100.prepend-top-5
= icon('lightbulb-o')
- if @page.persisted?
diff --git a/app/views/shared/wiki/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml
index 5e41bb6a9cd..2e1e176c42a 100644
--- a/app/views/shared/wiki/_main_links.html.haml
+++ b/app/views/projects/wikis/_main_links.html.haml
@@ -1,6 +1,6 @@
- if (@page && @page.persisted?)
- if can?(current_user, :create_wiki, @project)
- = link_to project_wiki_pages_new_path(@project), class: "add-new-wiki btn btn-success", role: "button" do
+ = link_to project_wikis_new_path(@project), class: "add-new-wiki btn btn-success", role: "button" do
= s_("Wiki|New page")
= link_to project_wiki_history_path(@project, @page), class: "btn", role: "button" do
= s_("Wiki|Page history")
diff --git a/app/views/projects/wikis/_pages_wiki_page.html.haml b/app/views/projects/wikis/_pages_wiki_page.html.haml
new file mode 100644
index 00000000000..c156f8cbf50
--- /dev/null
+++ b/app/views/projects/wikis/_pages_wiki_page.html.haml
@@ -0,0 +1,6 @@
+%li
+ = link_to wiki_page.title, project_wiki_path(@project, wiki_page)
+ %small (#{wiki_page.format})
+ .float-right
+ - if wiki_page.last_version
+ %small= (s_("Last edited %{date}") % { date: time_ago_with_tooltip(wiki_page.last_version.authored_date) }).html_safe
diff --git a/app/views/shared/wiki/_sidebar.html.haml b/app/views/projects/wikis/_sidebar.html.haml
index 83d145444d8..83d145444d8 100644
--- a/app/views/shared/wiki/_sidebar.html.haml
+++ b/app/views/projects/wikis/_sidebar.html.haml
diff --git a/app/views/projects/wikis/_sidebar_wiki_page.html.haml b/app/views/projects/wikis/_sidebar_wiki_page.html.haml
new file mode 100644
index 00000000000..769d869bd53
--- /dev/null
+++ b/app/views/projects/wikis/_sidebar_wiki_page.html.haml
@@ -0,0 +1,3 @@
+%li{ class: active_when(params[:id] == wiki_page.slug) }
+ = link_to project_wiki_path(@project, wiki_page) do
+ = wiki_page.human_title
diff --git a/app/views/projects/wikis/_wiki_directory.html.haml b/app/views/projects/wikis/_wiki_directory.html.haml
new file mode 100644
index 00000000000..0e5f32ed859
--- /dev/null
+++ b/app/views/projects/wikis/_wiki_directory.html.haml
@@ -0,0 +1,4 @@
+%li
+ = wiki_directory.slug
+ %ul
+ = render wiki_directory.pages, context: context
diff --git a/app/views/projects/wikis/_wiki_page.html.haml b/app/views/projects/wikis/_wiki_page.html.haml
new file mode 100644
index 00000000000..c84d06dad02
--- /dev/null
+++ b/app/views/projects/wikis/_wiki_page.html.haml
@@ -0,0 +1 @@
+= render "#{context}_wiki_page", wiki_page: wiki_page
diff --git a/app/views/projects/wiki_pages/edit.html.haml b/app/views/projects/wikis/edit.html.haml
index 4e5f6a077a4..9ccf5acfefc 100644
--- a/app/views/projects/wiki_pages/edit.html.haml
+++ b/app/views/projects/wikis/edit.html.haml
@@ -1,10 +1,5 @@
-- @content_class = 'edit-wiki-page' + (fluid_layout ? '' : ' limit-container-width')
-- add_to_breadcrumbs _("Wiki"), project_wiki_path(@project, :home)
-- add_to_breadcrumbs s_("Wiki|Pages"), project_wikis_pages_path(@project)
-- if @page.persisted? && @page_dir.present?
- - add_to_breadcrumbs _(@page_dir.slug), project_wiki_dir_path(@project, @page_dir)
-- if @page.persisted?
- - add_to_breadcrumbs @page.human_title, project_wiki_path(@project, @page)
+- @content_class = "limit-container-width" unless fluid_layout
+- add_to_breadcrumbs _("Wiki"), project_wiki_path(@project, @page)
- breadcrumb_title @page.persisted? ? _("Edit") : _("New")
- page_title @page.persisted? ? _("Edit") : _("New"), @page.human_title, _("Wiki")
@@ -17,7 +12,10 @@
.nav-text
%h2.wiki-page-title
- if @page.persisted?
- = render partial: 'page_title', locals: { subtitle: s_("Wiki|Edit Page") }
+ = link_to @page.human_title, project_wiki_path(@project, @page)
+ %span.light
+ &middot;
+ = s_("Wiki|Edit Page")
- else
= s_("Wiki|Create New Page")
diff --git a/app/views/projects/wiki_pages/missing_page.html.haml b/app/views/projects/wikis/empty.html.haml
index 62fa6e1907b..62fa6e1907b 100644
--- a/app/views/projects/wiki_pages/missing_page.html.haml
+++ b/app/views/projects/wikis/empty.html.haml
diff --git a/app/views/projects/wiki_pages/history.html.haml b/app/views/projects/wikis/history.html.haml
index d60a32750df..d3a55c53649 100644
--- a/app/views/projects/wiki_pages/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -1,4 +1,3 @@
-- @content_class = 'wiki-history'
- page_title _("History"), @page.human_title, _("Wiki")
.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row
@@ -7,7 +6,10 @@
.nav-text
%h2.wiki-page-title
- = render partial: 'page_title', locals: { subtitle: _("History") }
+ = link_to @page.human_title, project_wiki_path(@project, @page)
+ %span.light
+ &middot;
+ = _("History")
.table-holder
%table.table
@@ -37,4 +39,4 @@
= version.format
= paginate @page_versions, theme: 'gitlab'
-= render 'shared/wiki/sidebar'
+= render 'sidebar'
diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml
new file mode 100644
index 00000000000..d9dcd8f9acd
--- /dev/null
+++ b/app/views/projects/wikis/pages.html.haml
@@ -0,0 +1,32 @@
+- add_to_breadcrumbs "Wiki", project_wiki_path(@project, :home)
+- breadcrumb_title s_("Wiki|Pages")
+- page_title s_("Wiki|Pages"), _("Wiki")
+- sort_title = wiki_sort_title(params[:sort])
+
+.wiki-page-header.top-area.flex-column.flex-lg-row
+
+ .nav-text.flex-fill
+ %h2.wiki-page-title
+ = s_("Wiki|Wiki Pages")
+
+ .nav-controls.pb-md-3.pb-lg-0
+ = link_to project_wikis_git_access_path(@project), class: 'btn' do
+ = icon('cloud-download')
+ = _("Clone repository")
+
+ .dropdown.inline.wiki-sort-dropdown
+ .btn-group{ role: 'group' }
+ .btn-group{ role: 'group' }
+ %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'btn btn-default' }
+ = sort_title
+ = icon('chevron-down')
+ %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
+ %li
+ = sortable_item(s_("Wiki|Title"), project_wikis_pages_path(@project, sort: ProjectWiki::TITLE_ORDER), sort_title)
+ = sortable_item(s_("Wiki|Created date"), project_wikis_pages_path(@project, sort: ProjectWiki::CREATED_AT_ORDER), sort_title)
+ = wiki_sort_controls(@project, params[:sort], params[:direction])
+
+%ul.wiki-pages-list.content-list
+ = render @wiki_entries, context: 'pages'
+
+= paginate @wiki_pages, theme: 'gitlab'
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index 9c732a933cf..ebd99cf8605 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -1,5 +1,32 @@
-- add_to_breadcrumbs "Wiki", project_wiki_path(@project, :home)
-- breadcrumb_title s_("Wiki|Pages")
-- page_title s_("Wiki|Contents"), _("Wiki")
+- @content_class = "limit-container-width" unless fluid_layout
+- breadcrumb_title @page.human_title
+- wiki_breadcrumb_dropdown_links(@page.slug)
+- page_title @page.human_title, _("Wiki")
+- add_to_breadcrumbs _("Wiki"), project_wiki_path(@project, :home)
-= render 'page_listing', { allow_change_nesting: ::Feature.enabled?(:wikis_allow_change_nesting), wiki_page_title: page_title, page_path: ->(opts) { project_wikis_pages_path(@project, opts) } }
+.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row
+ %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
+ = icon('angle-double-left')
+
+ .nav-text.flex-fill
+ %h2.wiki-page-title= @page.human_title
+ %span.wiki-last-edit-by
+ - if @page.last_version
+ = (_("Last edited by %{name}") % { name: "<strong>#{@page.last_version.author_name}</strong>" }).html_safe
+ #{time_ago_with_tooltip(@page.last_version.authored_date)}
+
+ .nav-controls.pb-md-3.pb-lg-0
+ = render 'main_links'
+
+- if @page.historical?
+ .warning_message
+ = s_("WikiHistoricalPage|This is an old version of this page.")
+ - most_recent_link = link_to s_("WikiHistoricalPage|most recent version"), project_wiki_path(@project, @page)
+ - history_link = link_to s_("WikiHistoricalPage|history"), project_wiki_history_path(@project, @page)
+ = (s_("WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}.") % { most_recent_link: most_recent_link, history_link: history_link }).html_safe
+
+.prepend-top-default.append-bottom-default
+ .md.md-file{ data: { qa_selector: 'wiki_page_content' } }
+ = render_wiki_content(@page)
+
+= render 'sidebar'
diff --git a/app/views/shared/empty_states/_wikis.html.haml b/app/views/shared/empty_states/_wikis.html.haml
index e05230de457..73eedcc1dc9 100644
--- a/app/views/shared/empty_states/_wikis.html.haml
+++ b/app/views/shared/empty_states/_wikis.html.haml
@@ -1,11 +1,8 @@
- layout_path = 'shared/empty_states/wikis_layout'
-- wiki_is_empty = @project_wiki.empty?
-- empty_msg = wiki_is_empty ? s_('WikiEmpty|This project has no wiki pages') : s_('WikiEmpty|This page does not exist')
-- create_msg = wiki_is_empty ? s_('WikiEmpty|Create your first page') : s_('WikiEmpty|Create this page')
- if can?(current_user, :create_wiki, @project)
- create_path = project_wiki_path(@project, params[:id], { view: 'create' })
- - create_link = link_to create_msg, create_path, class: 'btn btn-success qa-create-first-page-link', title: create_msg
+ - create_link = link_to s_('WikiEmpty|Create your first page'), create_path, class: 'btn btn-success qa-create-first-page-link', title: s_('WikiEmpty|Create your first page')
= render layout: layout_path, locals: { image_path: 'illustrations/wiki_login_empty.svg' } do
%h4.text-left
@@ -20,7 +17,7 @@
= render layout: layout_path, locals: { image_path: 'illustrations/wiki_logout_empty.svg' } do
%h4
- = empty_msg
+ = s_('WikiEmpty|This project has no wiki pages')
%p.text-left
= s_('WikiEmptyIssueMessage|You must be a project member in order to add wiki pages. If you have suggestions for how to improve the wiki for this project, consider opening an issue in the %{issues_link}.').html_safe % { issues_link: issues_link }
= new_issue_link
@@ -28,6 +25,6 @@
- else
= render layout: layout_path, locals: { image_path: 'illustrations/wiki_logout_empty.svg' } do
%h4
- = empty_msg
+ = s_('WikiEmpty|This project has no wiki pages')
%p
= s_('WikiEmpty|You must be a project member in order to add wiki pages.')
diff --git a/app/views/shared/wiki/_page_listing.html.haml b/app/views/shared/wiki/_page_listing.html.haml
deleted file mode 100644
index 80f3071a8b2..00000000000
--- a/app/views/shared/wiki/_page_listing.html.haml
+++ /dev/null
@@ -1,45 +0,0 @@
-- @no_container = true
-- current_sorting = params.permit(:sort, :direction)
-- sort_title = wiki_sort_title(params[:sort])
-
-%div{ class: container_class }
- .wiki-page-header.top-area.flex-column.flex-lg-row
-
- .nav-text.flex-fill
- %h2.wiki-page-title
- = wiki_page_title
-
- .nav-controls.pb-md-3.pb-lg-0
- - if can?(current_user, :create_wiki, @project)
- = link_to project_wiki_pages_new_path(@project), class: "add-new-wiki btn btn-success" do
- = s_("Wiki|New page")
-
- = link_to project_wikis_git_access_path(@project), class: 'btn qa-clone-repository-link' do
- = sprite_icon('download', size: 16)
- = _("Clone repository")
-
- - if @nesting.present? && allow_change_nesting
- .dropdown.inline.wiki-nesting-dropdown
- .btn-group{ role: 'group' }
- %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'btn btn-default' }
- = wiki_show_children_icon(@nesting)
- = sprite_icon('chevron-down', size: 16)
- %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
- - ProjectWiki::NESTINGS.each do |choice|
- %li= link_to wiki_show_children_icon(choice), page_path.call(current_sorting.merge(show_children: choice)), class: @nesting == choice ? 'is-active' : ''
-
- .dropdown.inline.wiki-sort-dropdown
- .btn-group{ role: 'group' }
- %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'btn btn-default' }
- = sort_title
- = sprite_icon('chevron-down', size: 16)
- %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
- %li
- = sortable_item(s_("Wiki|Title"), page_path.call(sort: ProjectWiki::TITLE_ORDER), sort_title)
- = sortable_item(s_("Wiki|Created date"), page_path.call(sort: ProjectWiki::CREATED_AT_ORDER), sort_title)
- = wiki_sort_controls(current_sorting.merge(show_children: @nesting), &page_path)
-
- %ul.wiki-pages-list.content-list
- = render @wiki_entries, context: 'pages'
-
- = paginate @wiki_pages, theme: 'gitlab'
diff --git a/changelogs/unreleased/34230-fix-popover-image.yml b/changelogs/unreleased/34230-fix-popover-image.yml
new file mode 100644
index 00000000000..c9cf230ac6c
--- /dev/null
+++ b/changelogs/unreleased/34230-fix-popover-image.yml
@@ -0,0 +1,5 @@
+---
+title: Fix cluster feature highlight popover image
+merge_request: 19372
+author:
+type: fixed
diff --git a/changelogs/unreleased/add-snowplow-iglu-registry-application-setting.yml b/changelogs/unreleased/add-snowplow-iglu-registry-application-setting.yml
new file mode 100644
index 00000000000..b1e7447eaad
--- /dev/null
+++ b/changelogs/unreleased/add-snowplow-iglu-registry-application-setting.yml
@@ -0,0 +1,5 @@
+---
+title: Add ApplicationSetting for snowplow_iglu_registry_url
+merge_request: 18449
+author:
+type: added
diff --git a/changelogs/unreleased/sort-wiki-pages-by-date.yml b/changelogs/unreleased/sort-wiki-pages-by-date.yml
deleted file mode 100644
index be5238fd6c3..00000000000
--- a/changelogs/unreleased/sort-wiki-pages-by-date.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Sort wiki pages by date
-merge_request: 30245
-type: added
diff --git a/config/routes/project.rb b/config/routes/project.rb
index cc86e318dae..a132fb62647 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -617,7 +617,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
# Since both wiki and repository routing contains wildcard characters
- # its preferable to keep them below all other project routes
+ # its preferable to keep it below all other project routes
draw :wiki
draw :repository
diff --git a/config/routes/wiki.rb b/config/routes/wiki.rb
index 3e71c5eb924..d439c99270e 100644
--- a/config/routes/wiki.rb
+++ b/config/routes/wiki.rb
@@ -1,21 +1,13 @@
scope(controller: :wikis) do
- scope(path: 'wikis/pages', as: :wiki_pages, format: false) do
- get :new, to: 'wiki_pages#new'
- post '/', to: 'wiki_pages#create'
- end
-
scope(path: 'wikis', as: :wikis) do
get :git_access
get :pages
- get '/', to: redirect('%{namespace_id}/%{project_id}/-/wiki_pages/home')
- get '/*id', to: redirect('%{namespace_id}/%{project_id}/-/wiki_pages/%{id}')
- end
-
- scope(path: '-/wiki_pages', as: :wiki_page, format: false) do
- post '/', to: 'wiki_pages#create'
+ get :new
+ get '/', to: redirect('%{namespace_id}/%{project_id}/wikis/home')
+ post '/', to: 'wikis#create'
end
- scope(path: '-/wiki_pages/*id', as: :wiki, format: false, controller: :wiki_pages) do
+ scope(path: 'wikis/*id', as: :wiki, format: false) do
get :edit
get :history
post :preview_markdown
@@ -23,8 +15,4 @@ scope(controller: :wikis) do
put '/', action: :update
delete '/', action: :destroy
end
-
- scope(path: '-/wiki_dirs/*id', as: :wiki_dir, format: false, controller: :wiki_directories) do
- get '/', action: :show
- end
end
diff --git a/db/migrate/20191010174846_add_snowplow_iglu_registry_url_to_application_settings.rb b/db/migrate/20191010174846_add_snowplow_iglu_registry_url_to_application_settings.rb
new file mode 100644
index 00000000000..a40ce8dbee5
--- /dev/null
+++ b/db/migrate/20191010174846_add_snowplow_iglu_registry_url_to_application_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddSnowplowIgluRegistryUrlToApplicationSettings < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column :application_settings, :snowplow_iglu_registry_url, :string, limit: 255
+ end
+end
diff --git a/db/migrate/20191024134020_add_index_to_zoom_meetings.rb b/db/migrate/20191024134020_add_index_to_zoom_meetings.rb
new file mode 100644
index 00000000000..ef3657b6a5e
--- /dev/null
+++ b/db/migrate/20191024134020_add_index_to_zoom_meetings.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexToZoomMeetings < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :zoom_meetings, :issue_status
+ end
+
+ def down
+ remove_concurrent_index :zoom_meetings, :issue_status if index_exists?(:zoom_meetings, :issue_status)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index df56b84d61b..b07ba57ba77 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -338,6 +338,7 @@ ActiveRecord::Schema.define(version: 2019_10_26_124116) do
t.boolean "throttle_incident_management_notification_enabled", default: false, null: false
t.integer "throttle_incident_management_notification_period_in_seconds", default: 3600
t.integer "throttle_incident_management_notification_per_period", default: 3600
+ t.string "snowplow_iglu_registry_url", limit: 255
t.integer "push_event_hooks_limit", default: 3, null: false
t.integer "push_event_activities_limit", default: 3, null: false
t.string "custom_http_clone_url_root", limit: 511
@@ -4041,6 +4042,7 @@ ActiveRecord::Schema.define(version: 2019_10_26_124116) do
t.string "url", limit: 255
t.index ["issue_id", "issue_status"], name: "index_zoom_meetings_on_issue_id_and_issue_status", unique: true, where: "(issue_status = 1)"
t.index ["issue_id"], name: "index_zoom_meetings_on_issue_id"
+ t.index ["issue_status"], name: "index_zoom_meetings_on_issue_status"
t.index ["project_id"], name: "index_zoom_meetings_on_project_id"
end
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 36419ae8ec4..a1c343ec208 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -316,6 +316,7 @@ are listed in the descriptions of the relevant settings.
| `snowplow_cookie_domain` | string | no | The Snowplow cookie domain. (e.g. `.gitlab.com`) |
| `snowplow_enabled` | boolean | no | Enable snowplow tracking. |
| `snowplow_site_id` | string | no | The Snowplow site name / application id. (e.g. `gitlab`) |
+| `snowplow_iglu_registry_url` | string | no | The Snowplow base Iglu Schema Registry URL to use for custom context and self describing events'|
| `pendo_url` | string | required by: `pendo_enabled` | The Pendo endpoint url with js snippet. (e.g. `https://cdn.pendo.io/agent/static/your-api-key/pendo.js`) |
| `pendo_enabled` | boolean | no | Enable pendo tracking. |
| `terminal_max_session_time` | integer | no | Maximum time for web terminal websocket connection (in seconds). Set to `0` for unlimited time. |
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index ffa0472bdbb..0772423dcb7 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -135,6 +135,7 @@ module API
optional :local_markdown_version, type: Integer, desc: 'Local markdown version, increase this value when any cached markdown should be invalidated'
optional :allow_local_requests_from_hooks_and_services, type: Boolean, desc: 'Deprecated: Use :allow_local_requests_from_web_hooks_and_services instead. Allow requests to the local network from hooks and services.' # support legacy names, can be removed in v5
optional :snowplow_enabled, type: Grape::API::Boolean, desc: 'Enable Snowplow tracking'
+ optional :snowplow_iglu_registry_url, type: String, desc: 'The Snowplow base Iglu Schema Registry URL to use for custom context and self describing events'
given snowplow_enabled: ->(val) { val } do
requires :snowplow_collector_hostname, type: String, desc: 'The Snowplow collector hostname'
optional :snowplow_cookie_domain, type: String, desc: 'The Snowplow cookie domain'
diff --git a/lib/banzai/filter/wiki_link_filter/rewriter.rb b/lib/banzai/filter/wiki_link_filter/rewriter.rb
index e346b03754b..f4cc8beeb52 100644
--- a/lib/banzai/filter/wiki_link_filter/rewriter.rb
+++ b/lib/banzai/filter/wiki_link_filter/rewriter.rb
@@ -6,7 +6,7 @@ module Banzai
class Rewriter
def initialize(link_string, wiki:, slug:)
@uri = Addressable::URI.parse(link_string)
- @wiki_base_path = wiki && wiki.wiki_page_path
+ @wiki_base_path = wiki && wiki.wiki_base_path
@slug = slug
end
diff --git a/lib/gitlab/tracking.rb b/lib/gitlab/tracking.rb
index 2470685bc00..af6b13b0d36 100644
--- a/lib/gitlab/tracking.rb
+++ b/lib/gitlab/tracking.rb
@@ -47,7 +47,8 @@ module Gitlab
cookie_domain: Gitlab::CurrentSettings.snowplow_cookie_domain,
app_id: Gitlab::CurrentSettings.snowplow_site_id,
form_tracking: additional_features,
- link_click_tracking: additional_features
+ link_click_tracking: additional_features,
+ iglu_registry_url: Gitlab::CurrentSettings.snowplow_iglu_registry_url
}.transform_keys! { |key| key.to_s.camelize(:lower).to_sym }
end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 504780d0402..76324b93799 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -78,6 +78,8 @@ module Gitlab
in_review_folder: count(::Environment.in_review_folder),
groups: count(Group),
issues: count(Issue),
+ issues_with_associated_zoom_link: count(ZoomMeeting.added_to_issue),
+ issues_using_zoom_quick_actions: count(ZoomMeeting.select(:issue_id).distinct),
keys: count(Key),
label_lists: count(List.label),
lfs_objects: count(LfsObject),
diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb
index 5cba6c52773..7fbfc4c45c4 100644
--- a/lib/gitlab/utils.rb
+++ b/lib/gitlab/utils.rb
@@ -130,15 +130,5 @@ module Gitlab
IPAddr.new(str)
rescue IPAddr::InvalidAddressError
end
-
- # Filter a Hash against a mapping of keys to sets of allowed values.
- #
- # Keys that do not pass the filter will be removed from the Hash.
- # This mutates the input hash.
- def allow_hash_values(hash, allowed)
- allowed.each do |key, allowed_values|
- hash.delete(key) if hash.key?(key) && !allowed_values.include?(hash[key])
- end
- end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 193eddc191d..b0a5500a38d 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -411,9 +411,6 @@ msgstr ""
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
-msgid "&middot;"
-msgstr ""
-
msgid "'%{level}' is not a valid visibility level"
msgstr ""
@@ -8848,6 +8845,9 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
+msgid "Iglu registry URL (optional)"
+msgstr ""
+
msgid "ImageDiffViewer|2-up"
msgstr ""
@@ -9543,6 +9543,9 @@ msgstr ""
msgid "Kubernetes error: %{error_code}"
msgstr ""
+msgid "Kubernetes popover"
+msgstr ""
+
msgid "LDAP"
msgstr ""
@@ -18891,10 +18894,7 @@ msgstr ""
msgid "Wiki pages"
msgstr ""
-msgid "Wiki was successfully created"
-msgstr ""
-
-msgid "Wiki was successfully updated"
+msgid "Wiki was successfully updated."
msgstr ""
msgid "WikiClone|Clone your wiki"
@@ -18912,18 +18912,6 @@ msgstr ""
msgid "WikiClone|Start Gollum and edit locally"
msgstr ""
-msgid "WikiDirEmpty|A wiki is where you can store all the details about your project. This can include why you've created it, its principles, how to use it, and so on."
-msgstr ""
-
-msgid "WikiDirEmpty|Create a page"
-msgstr ""
-
-msgid "WikiDirEmpty|Create a page in this directory"
-msgstr ""
-
-msgid "WikiDirEmpty|This directory has no wiki pages"
-msgstr ""
-
msgid "WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title."
msgstr ""
@@ -18942,9 +18930,6 @@ msgstr ""
msgid "WikiEmpty|A wiki is where you can store all the details about your project. This can include why you've created it, its principles, how to use it, and so on."
msgstr ""
-msgid "WikiEmpty|Create this page"
-msgstr ""
-
msgid "WikiEmpty|Create your first page"
msgstr ""
@@ -18954,9 +18939,6 @@ msgstr ""
msgid "WikiEmpty|The wiki lets you write documentation for your project"
msgstr ""
-msgid "WikiEmpty|This page does not exist"
-msgstr ""
-
msgid "WikiEmpty|This project has no wiki pages"
msgstr ""
@@ -19011,9 +18993,6 @@ msgstr ""
msgid "WikiPage|Write your content or drag files here…"
msgstr ""
-msgid "Wiki|Contents"
-msgstr ""
-
msgid "Wiki|Create New Page"
msgstr ""
@@ -19026,9 +19005,6 @@ msgstr ""
msgid "Wiki|Edit Page"
msgstr ""
-msgid "Wiki|Hide folder contents"
-msgstr ""
-
msgid "Wiki|More Pages"
msgstr ""
@@ -19047,13 +19023,10 @@ msgstr ""
msgid "Wiki|Pages"
msgstr ""
-msgid "Wiki|Show files separately"
-msgstr ""
-
-msgid "Wiki|Show folder contents"
+msgid "Wiki|Title"
msgstr ""
-msgid "Wiki|Title"
+msgid "Wiki|Wiki Pages"
msgstr ""
msgid "Will deploy to"
diff --git a/qa/qa/page/project/wiki/edit.rb b/qa/qa/page/project/wiki/edit.rb
index bdc1cda8950..f6edc28c41a 100644
--- a/qa/qa/page/project/wiki/edit.rb
+++ b/qa/qa/page/project/wiki/edit.rb
@@ -5,7 +5,7 @@ module QA
module Project
module Wiki
class Edit < Page::Base
- view 'app/views/shared/wiki/_main_links.html.haml' do
+ view 'app/views/projects/wikis/_main_links.html.haml' do
element :new_page_link, 'New page' # rubocop:disable QA/ElementWithPattern
element :page_history_link, 'Page history' # rubocop:disable QA/ElementWithPattern
element :edit_page_link, 'Edit' # rubocop:disable QA/ElementWithPattern
diff --git a/qa/qa/page/project/wiki/new.rb b/qa/qa/page/project/wiki/new.rb
index abad499d700..792eba4bab7 100644
--- a/qa/qa/page/project/wiki/new.rb
+++ b/qa/qa/page/project/wiki/new.rb
@@ -7,7 +7,7 @@ module QA
class New < Page::Base
include Component::LazyLoader
- view 'app/views/projects/wiki_pages/_form.html.haml' do
+ view 'app/views/projects/wikis/_form.html.haml' do
element :wiki_title_textbox
element :wiki_content_textarea
element :wiki_message_textbox
diff --git a/qa/qa/page/project/wiki/show.rb b/qa/qa/page/project/wiki/show.rb
index c6b34ddc317..44619d177b1 100644
--- a/qa/qa/page/project/wiki/show.rb
+++ b/qa/qa/page/project/wiki/show.rb
@@ -7,11 +7,11 @@ module QA
class Show < Page::Base
include Page::Component::LegacyClonePanel
- view 'app/views/shared/wiki/_page_listing.html.haml' do
+ view 'app/views/projects/wikis/pages.html.haml' do
element :clone_repository_link, 'Clone repository' # rubocop:disable QA/ElementWithPattern
end
- view 'app/views/projects/wiki_pages/show.html.haml' do
+ view 'app/views/projects/wikis/show.html.haml' do
element :wiki_page_content
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb
index b996492ce08..2c3f2c86c23 100644
--- a/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb
@@ -13,7 +13,7 @@ module QA
resource.message = 'Update home'
end
- validate_created('My First Wiki Content')
+ validate_content('My First Wiki Content')
Page::Project::Wiki::Edit.perform(&:click_edit)
Page::Project::Wiki::New.perform do |page| # rubocop:disable QA/AmbiguousPageObjectName
@@ -21,7 +21,7 @@ module QA
page.save_changes
end
- validate_edited('My Second Wiki Content')
+ validate_content('My Second Wiki Content')
Resource::Repository::WikiPush.fabricate! do |push|
push.wiki = wiki
@@ -34,12 +34,7 @@ module QA
expect(page).to have_content('My Third Wiki Content')
end
- def validate_created(content)
- expect(page).to have_content('Wiki was successfully created')
- expect(page).to have_content(/#{content}/)
- end
-
- def validate_edited(content)
+ def validate_content(content)
expect(page).to have_content('Wiki was successfully updated')
expect(page).to have_content(/#{content}/)
end
diff --git a/scripts/static-analysis b/scripts/static-analysis
index 602cd847a71..b7f7100c365 100755
--- a/scripts/static-analysis
+++ b/scripts/static-analysis
@@ -26,17 +26,35 @@ def emit_errors(static_analysis)
end
end
-tasks = [
- %w[bin/rake lint:all],
- %w[bundle exec license_finder],
- %w[yarn run eslint],
- %w[yarn run stylelint],
- %w[yarn run prettier-all],
- %w[bundle exec rubocop --parallel],
- %w[scripts/lint-conflicts.sh],
- %w[scripts/lint-rugged]
-]
+def jobs_to_run(node_index, node_total)
+ all_tasks = [
+ %w[bin/rake lint:all],
+ %w[bundle exec license_finder],
+ %w[yarn run eslint],
+ %w[yarn run stylelint],
+ %w[yarn run prettier-all],
+ %w[bundle exec rubocop --parallel],
+ %w[scripts/lint-conflicts.sh],
+ %w[scripts/lint-rugged]
+ ]
+ case node_total
+ when 1
+ all_tasks
+ when 2
+ rake_lint_all, *rest_jobs = all_tasks
+ case node_index
+ when 1
+ [rake_lint_all]
+ else
+ rest_jobs
+ end
+ else
+ raise "Parallelization > 2 (currently set to #{node_total}) isn't supported yet!"
+ end
+end
+
+tasks = jobs_to_run((ENV['CI_NODE_INDEX'] || 1).to_i, (ENV['CI_NODE_TOTAL'] || 1).to_i)
static_analysis = Gitlab::Popen::Runner.new
static_analysis.run(tasks) do |cmd, &run|
diff --git a/spec/controllers/projects/wiki_directories_controller_spec.rb b/spec/controllers/projects/wiki_directories_controller_spec.rb
deleted file mode 100644
index b09e1bc2ca4..00000000000
--- a/spec/controllers/projects/wiki_directories_controller_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe Projects::WikiDirectoriesController do
- set(:project) { create(:project, :public, :repository) }
-
- let(:user) { project.owner }
- let(:project_wiki) { ProjectWiki.new(project, user) }
- let(:wiki) { project_wiki.wiki }
- let(:dir_slug) { 'the-directory' }
- let(:dir_contents) { [create(:wiki_page)] }
- let(:the_dir) { WikiDirectory.new(dir_slug, dir_contents) }
-
- before do
- allow(controller).to receive(:find_dir).and_return(the_dir)
-
- sign_in(user)
- end
-
- describe 'GET #show' do
- let(:show_params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- id: dir_slug
- }
- end
-
- before do
- get :show, params: show_params
- end
-
- context 'the directory is empty' do
- let(:the_dir) { nil }
-
- it { is_expected.to render_template('empty') }
- end
-
- context 'the directory does exist' do
- it { is_expected.to render_template('show') }
-
- it 'sets the wiki_dir attribute' do
- expect(assigns(:wiki_dir)).to eq(the_dir)
- end
-
- it 'assigns the wiki pages' do
- expect(assigns(:wiki_pages)).to eq(dir_contents)
- end
- end
- end
-end
diff --git a/spec/controllers/projects/wiki_pages_controller_spec.rb b/spec/controllers/projects/wiki_pages_controller_spec.rb
deleted file mode 100644
index 01a84fbbf20..00000000000
--- a/spec/controllers/projects/wiki_pages_controller_spec.rb
+++ /dev/null
@@ -1,399 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe Projects::WikiPagesController do
- set(:project) { create(:project, :public, :repository) }
- let(:user) { project.owner }
- let(:project_wiki) { ProjectWiki.new(project, user) }
- let(:wiki) { project_wiki.wiki }
- let(:wiki_title) { 'page-title-test' }
- let(:parent_ids) { { namespace_id: project.namespace.path, project_id: project.name } }
- let(:redirect_destination) { Rails.application.routes.recognize_path(response.redirect_url) }
-
- before do
- create_page(wiki_title, 'hello world')
-
- sign_in(user)
- end
-
- after do
- destroy_page(wiki_title)
- end
-
- def helper
- Helper.instance
- end
-
- class Helper
- include Singleton
- include ActionView::Helpers::UrlHelper
- end
-
- describe 'GET #new' do
- subject { get :new, params: parent_ids }
-
- it 'redirects to #show and appends a `random_title` param' do
- subject
-
- expect(response).to have_http_status(302)
-
- expect(redirect_destination)
- .to include(parent_ids.merge(controller: 'projects/wiki_pages', action: 'show'))
-
- expect(response.redirect_url).to match(/\?random_title=true\Z/)
- end
- end
-
- describe 'GET #show' do
- render_views
- let(:requested_wiki_page) { wiki_title }
- let(:random_title) { nil }
-
- subject do
- get :show, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: requested_wiki_page,
- random_title: random_title
- }
- end
-
- context 'when the wiki repo cannot be created' do
- before do
- allow(controller).to receive(:load_wiki) { raise ProjectWiki::CouldNotCreateWikiError }
- end
-
- it 'redirects to the project path' do
- headers = { 'Location' => a_string_ending_with(Gitlab::Routing.url_helpers.project_path(project)) }
-
- subject
-
- expect(response).to be_redirect
- expect(response.header.to_hash).to include(headers)
- end
- end
-
- context 'when the page exists' do
- it 'limits the retrieved pages for the sidebar' do
- expect(controller).to receive(:load_wiki).and_return(project_wiki)
-
- # Sidebar entries
- expect(project_wiki).to receive(:list_pages).with(limit: 15).and_call_original
-
- subject
-
- expect(response).to have_http_status(:ok)
- expect(response.body).to include(wiki_title)
- end
-
- context 'when page content encoding is invalid' do
- it 'sets flash error' do
- allow(controller).to receive(:valid_encoding?).and_return(false)
-
- subject
-
- expect(response).to have_http_status(:ok)
- expect(flash[:notice]).to eq 'The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.'
- end
- end
- end
-
- context 'when the page does not exist' do
- let(:requested_wiki_page) { 'this-page-does-not-yet-exist' }
-
- context 'the current user can create wiki pages' do
- it { is_expected.to render_template('edit') }
-
- it 'makes a call to see if the wiki is empty' do
- expect(controller).to receive(:load_wiki).and_return(project_wiki)
- expect(project_wiki).to receive(:list_pages).once.with(limit: anything).and_call_original
- expect(project_wiki).to receive(:list_pages).with(limit: 1).and_call_original
- subject
- end
-
- describe 'assigned title' do
- shared_examples :wiki_page_with_correct_title do
- it 'assigns the correct title' do
- subject
-
- expect(assigns(:page)).to have_attributes(title: assigned_title)
- end
- end
-
- context 'random_title is absent' do
- let(:random_title) { nil }
-
- it_behaves_like :wiki_page_with_correct_title do
- let(:assigned_title) { WikiPage.unhyphenize(requested_wiki_page) }
- end
- end
-
- context 'random_title is present' do
- let(:random_title) { true }
-
- it_behaves_like :wiki_page_with_correct_title do
- let(:assigned_title) { be_empty }
- end
- end
- end
- end
-
- context 'the current user cannot create wiki pages' do
- before do
- forbid_controller_ability! :create_wiki
- end
- it { is_expected.to render_template('missing_page') }
- end
- end
-
- context 'when page is a file' do
- include WikiHelpers
-
- let(:path) { upload_file_to_wiki(project, user, file_name) }
-
- before do
- get :show, params: { namespace_id: project.namespace, project_id: project, id: path }
- end
-
- context 'when file is an image' do
- let(:file_name) { 'dk.png' }
-
- it 'delivers the image' do
- expect(response.headers['Content-Disposition']).to match(/^inline/)
- expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- end
-
- context 'when file is a svg' do
- let(:file_name) { 'unsanitized.svg' }
-
- it 'delivers the image' do
- expect(response.headers['Content-Disposition']).to match(/^inline/)
- expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- end
- end
- end
-
- context 'when file is a pdf' do
- let(:file_name) { 'git-cheat-sheet.pdf' }
-
- it 'sets the content type to sets the content response headers' do
- expect(response.headers['Content-Disposition']).to match(/^inline/)
- expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- end
- end
- end
- end
-
- describe 'POST #preview_markdown' do
- let(:page_id) { 'page/path' }
- let(:markdown_text) { '*Markdown* text' }
- let(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: wiki_title }) }
- let(:processed_md) { json_response.fetch('body') }
-
- let(:preview_params) do
- { namespace_id: project.namespace, project_id: project, id: wiki_page.slug, text: markdown_text }
- end
-
- before do
- post :preview_markdown, params: preview_params
- end
-
- it 'renders json in a correct format' do
- expect(response).to have_http_status(:ok)
- expect(json_response).to include('body' => String, 'references' => Hash)
- end
-
- describe 'double brackets within backticks' do
- let(:markdown_text) do
- <<-HEREDOC
- `[[do_not_linkify]]`
- ```
- [[also_do_not_linkify]]
- ```
- HEREDOC
- end
-
- it "does not linkify double brackets inside code blocks as expected" do
- expect(processed_md).to include('[[do_not_linkify]]', '[[also_do_not_linkify]]')
- end
- end
-
- describe 'link re-writing' do
- let(:links) do
- [
- { text: 'regular link', path: 'regular' },
- { text: 'relative link 1', path: '../relative' },
- { text: 'relative link 2', path: './relative' },
- { text: 'relative link 3', path: './e/f/relative' },
- { text: 'spaced link', path: 'title with spaces' }
- ]
- end
-
- shared_examples :wiki_link_rewriter do
- let(:markdown_text) { links.map { |text:, path:| "[#{text}](#{path})" }.join("\n") }
- let(:expected_links) do
- links.zip(paths).map do |(link, path)|
- helper.link_to(link[:text], "#{project_wiki.wiki_page_path}/#{path}")
- end
- end
-
- it 'processes the links correctly' do
- expect(processed_md).to include(*expected_links)
- end
- end
-
- context 'the current page has spaces in its title' do
- let(:wiki_title) { 'page a/page b/page c/page d' }
- it_behaves_like :wiki_link_rewriter do
- let(:paths) do
- ['regular',
- 'page-a/page-b/relative',
- 'page-a/page-b/page-c/relative',
- 'page-a/page-b/page-c/e/f/relative',
- 'title%20with%20spaces']
- end
- end
- end
-
- context 'the current page has an unproblematic title' do
- let(:wiki_title) { 'a/b/c/d' }
- it_behaves_like :wiki_link_rewriter do
- let(:paths) do
- ['regular', 'a/b/relative', 'a/b/c/relative', 'a/b/c/e/f/relative', 'title%20with%20spaces']
- end
- end
- end
-
- context "when there are hyphens in the page name" do
- let(:wiki_title) { 'page-a/page-b/page-c/page-d' }
- it_behaves_like :wiki_link_rewriter do
- let(:paths) do
- ['regular',
- 'page-a/page-b/relative',
- 'page-a/page-b/page-c/relative',
- 'page-a/page-b/page-c/e/f/relative',
- 'title%20with%20spaces']
- end
- end
- end
- end
- end
-
- describe 'GET #edit' do
- subject { get(:edit, params: { namespace_id: project.namespace, project_id: project, id: wiki_title }) }
-
- context 'when page content encoding is invalid' do
- it 'redirects to show' do
- allow(controller).to receive(:valid_encoding?).and_return(false)
-
- subject
-
- expect(response).to redirect_to(project_wiki_path(project, project_wiki.list_pages.first))
- end
- end
-
- context 'when page content encoding is valid' do
- render_views
-
- it 'shows the edit page' do
- subject
-
- expect(response).to have_http_status(:ok)
- expect(response.body).to include('Edit Page')
- end
- end
- end
-
- describe 'PATCH #update' do
- let(:new_title) { 'New title' }
- let(:new_content) { 'New content' }
- subject do
- patch(:update,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: wiki_title,
- wiki_page: { title: new_title, content: new_content }
- })
- end
-
- context 'when page content encoding is invalid' do
- it 'redirects to show' do
- allow(controller).to receive(:valid_encoding?).and_return(false)
-
- subject
- expect(response).to redirect_to(project_wiki_path(project, project_wiki.list_pages.first))
- end
- end
-
- context 'when page content encoding is valid' do
- render_views
-
- it 'updates the page' do
- subject
-
- wiki_page = project_wiki.list_pages(load_content: true).first
-
- expect(wiki_page.title).to eq new_title
- expect(wiki_page.content).to eq new_content
- end
- end
- end
-
- describe 'GET #history' do
- before do
- allow(controller)
- .to receive(:can?)
- .with(any_args)
- .and_call_original
-
- # The :create_wiki permission is irrelevant to reading history.
- expect(controller)
- .not_to receive(:can?)
- .with(anything, :create_wiki, any_args)
-
- allow(controller)
- .to receive(:can?)
- .with(anything, :read_wiki, any_args)
- .and_return(allow_read_wiki)
- end
-
- shared_examples 'fetching history' do |expected_status|
- before do
- get :history, params: { namespace_id: project.namespace, project_id: project, id: wiki_title }
- end
-
- it "returns status #{expected_status}" do
- expect(response).to have_http_status(expected_status)
- end
- end
-
- it_behaves_like 'fetching history', :ok do
- let(:allow_read_wiki) { true }
-
- it 'assigns @page_versions' do
- expect(assigns(:page_versions)).to be_present
- end
- end
-
- it_behaves_like 'fetching history', :not_found do
- let(:allow_read_wiki) { false }
- end
- end
-
- private
-
- def create_page(name, content)
- wiki.write_page(name, :markdown, content, commit_details(name))
- end
-
- def commit_details(name)
- Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.email, "created page #{name}")
- end
-
- def destroy_page(title, dir = '')
- page = wiki.page(title: title, dir: dir)
- project_wiki.delete_page(page, "test commit")
- end
-end
diff --git a/spec/controllers/projects/wikis_controller_spec.rb b/spec/controllers/projects/wikis_controller_spec.rb
index 7fbefa5787b..f46da908218 100644
--- a/spec/controllers/projects/wikis_controller_spec.rb
+++ b/spec/controllers/projects/wikis_controller_spec.rb
@@ -4,10 +4,10 @@ require 'spec_helper'
describe Projects::WikisController do
let_it_be(:project) { create(:project, :public, :repository) }
- let_it_be(:user) { project.owner }
- let_it_be(:project_wiki) { ProjectWiki.new(project, user) }
- let_it_be(:wiki) { project_wiki.wiki }
- let_it_be(:wiki_title) { 'page title test' }
+ let(:user) { project.owner }
+ let(:project_wiki) { ProjectWiki.new(project, user) }
+ let(:wiki) { project_wiki.wiki }
+ let(:wiki_title) { 'page title test' }
before do
create_page(wiki_title, 'hello world')
@@ -19,86 +19,231 @@ describe Projects::WikisController do
destroy_page(wiki_title)
end
- describe 'GET #pages' do
- subject do
- get :pages, params: { namespace_id: project.namespace, project_id: project, id: wiki_title }.merge(extra_params)
+ describe 'GET #new' do
+ subject { get :new, params: { namespace_id: project.namespace, project_id: project } }
+
+ it 'redirects to #show and appends a `random_title` param' do
+ subject
+
+ expect(response).to have_http_status(302)
+ expect(Rails.application.routes.recognize_path(response.redirect_url)).to include(
+ controller: 'projects/wikis',
+ action: 'show'
+ )
+ expect(response.redirect_url).to match(/\?random_title=true\Z/)
end
+ end
- let(:extra_params) { {} }
+ describe 'GET #pages' do
+ subject { get :pages, params: { namespace_id: project.namespace, project_id: project, id: wiki_title } }
it 'does not load the pages content' do
expect(controller).to receive(:load_wiki).and_return(project_wiki)
+
expect(project_wiki).to receive(:list_pages).twice.and_call_original
subject
end
+ end
- describe 'illegal params' do
- shared_examples :a_bad_request do
- it do
- expect { subject }.to raise_error(ActionController::BadRequest)
- end
- end
+ describe 'GET #history' do
+ before do
+ allow(controller)
+ .to receive(:can?)
+ .with(any_args)
+ .and_call_original
- describe ':sort' do
- let(:extra_params) { { sort: 'wibble' } }
+ # The :create_wiki permission is irrelevant to reading history.
+ expect(controller)
+ .not_to receive(:can?)
+ .with(anything, :create_wiki, any_args)
- it_behaves_like :a_bad_request
- end
+ allow(controller)
+ .to receive(:can?)
+ .with(anything, :read_wiki, any_args)
+ .and_return(allow_read_wiki)
+ end
- describe ':direction' do
- let(:extra_params) { { direction: 'wibble' } }
+ shared_examples 'fetching history' do |expected_status|
+ before do
+ get :history, params: { namespace_id: project.namespace, project_id: project, id: wiki_title }
+ end
- it_behaves_like :a_bad_request
+ it "returns status #{expected_status}" do
+ expect(response).to have_http_status(expected_status)
end
+ end
- describe ':show_children' do
- let(:extra_params) { { show_children: 'wibble' } }
+ it_behaves_like 'fetching history', :ok do
+ let(:allow_read_wiki) { true }
- it_behaves_like :a_bad_request
+ it 'assigns @page_versions' do
+ expect(assigns(:page_versions)).to be_present
end
end
- shared_examples 'sorting-and-nesting' do |sort_key, default_nesting|
- context "the user is sorting by #{sort_key}" do
- let(:extra_params) { sort_params.merge(nesting_params) }
- let(:sort_params) { { sort: sort_key } }
- let(:nesting_params) { {} }
+ it_behaves_like 'fetching history', :not_found do
+ let(:allow_read_wiki) { false }
+ end
+ end
+
+ describe 'GET #show' do
+ render_views
+
+ let(:random_title) { nil }
+
+ subject { get :show, params: { namespace_id: project.namespace, project_id: project, id: id, random_title: random_title } }
+
+ context 'when page exists' do
+ let(:id) { wiki_title }
+
+ it 'limits the retrieved pages for the sidebar' do
+ expect(controller).to receive(:load_wiki).and_return(project_wiki)
+ expect(project_wiki).to receive(:list_pages).with(limit: 15).and_call_original
+
+ subject
+
+ expect(response).to have_http_status(:ok)
+ expect(assigns(:page).title).to eq(wiki_title)
+ end
+
+ context 'when page content encoding is invalid' do
+ it 'sets flash error' do
+ allow(controller).to receive(:valid_encoding?).and_return(false)
- before do
subject
+
+ expect(response).to have_http_status(:ok)
+ expect(flash[:notice]).to eq('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.')
end
+ end
+ end
+
+ context 'when the page does not exist' do
+ let(:id) { 'does not exist' }
- it "sets nesting to #{default_nesting} by default" do
- expect(assigns :nesting).to eq default_nesting
+ before do
+ subject
+ end
+
+ it 'builds a new wiki page with the id as the title' do
+ expect(assigns(:page).title).to eq(id)
+ end
+
+ context 'when a random_title param is present' do
+ let(:random_title) { true }
+
+ it 'builds a new wiki page with no title' do
+ expect(assigns(:page).title).to be_empty
end
+ end
+ end
- it 'hides children if the default requires it' do
- expect(assigns :show_children).to be(default_nesting != ProjectWiki::NESTING_CLOSED)
+ context 'when page is a file' do
+ include WikiHelpers
+
+ let(:id) { upload_file_to_wiki(project, user, file_name) }
+
+ before do
+ subject
+ end
+
+ context 'when file is an image' do
+ let(:file_name) { 'dk.png' }
+
+ it 'delivers the image' do
+ expect(response.headers['Content-Disposition']).to match(/^inline/)
+ expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
- ProjectWiki::NESTINGS.each do |nesting|
- context "the user explicitly passes show_children = #{nesting}" do
- let(:nesting_params) { { show_children: nesting } }
+ context 'when file is a svg' do
+ let(:file_name) { 'unsanitized.svg' }
- it 'sets nesting to the provided value' do
- expect(assigns :nesting).to eq nesting
- end
+ it 'delivers the image' do
+ expect(response.headers['Content-Disposition']).to match(/^inline/)
+ expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
end
+ end
- context 'the user wants children hidden' do
- let(:nesting_params) { { show_children: 'hidden' } }
+ context 'when file is a pdf' do
+ let(:file_name) { 'git-cheat-sheet.pdf' }
- it 'hides children' do
- expect(assigns :show_children).to be false
- end
+ it 'sets the content type to sets the content response headers' do
+ expect(response.headers['Content-Disposition']).to match(/^inline/)
+ expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
end
end
+ end
+
+ describe 'POST #preview_markdown' do
+ it 'renders json in a correct format' do
+ post :preview_markdown, params: { namespace_id: project.namespace, project_id: project, id: 'page/path', text: '*Markdown* text' }
+
+ expect(json_response.keys).to match_array(%w(body references))
+ end
+ end
+
+ describe 'GET #edit' do
+ subject { get(:edit, params: { namespace_id: project.namespace, project_id: project, id: wiki_title }) }
+
+ context 'when page content encoding is invalid' do
+ it 'redirects to show' do
+ allow(controller).to receive(:valid_encoding?).and_return(false)
+
+ subject
+
+ expect(response).to redirect_to(project_wiki_path(project, project_wiki.list_pages.first))
+ end
+ end
- include_examples 'sorting-and-nesting', ProjectWiki::CREATED_AT_ORDER, ProjectWiki::NESTING_FLAT
- include_examples 'sorting-and-nesting', ProjectWiki::TITLE_ORDER, ProjectWiki::NESTING_CLOSED
+ context 'when page content encoding is valid' do
+ render_views
+
+ it 'shows the edit page' do
+ subject
+
+ expect(response).to have_http_status(:ok)
+ expect(response.body).to include('Edit Page')
+ end
+ end
+ end
+
+ describe 'PATCH #update' do
+ let(:new_title) { 'New title' }
+ let(:new_content) { 'New content' }
+ subject do
+ patch(:update,
+ params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: wiki_title,
+ wiki: { title: new_title, content: new_content }
+ })
+ end
+
+ context 'when page content encoding is invalid' do
+ it 'redirects to show' do
+ allow(controller).to receive(:valid_encoding?).and_return(false)
+
+ subject
+ expect(response).to redirect_to(project_wiki_path(project, project_wiki.list_pages.first))
+ end
+ end
+
+ context 'when page content encoding is valid' do
+ render_views
+
+ it 'updates the page' do
+ subject
+
+ wiki_page = project_wiki.list_pages(load_content: true).first
+
+ expect(wiki_page.title).to eq new_title
+ expect(wiki_page.content).to eq new_content
+ end
+ end
end
def create_page(name, content)
diff --git a/spec/factories/wiki_pages.rb b/spec/factories/wiki_pages.rb
index 3ac8fe4ae43..761ba58edb2 100644
--- a/spec/factories/wiki_pages.rb
+++ b/spec/factories/wiki_pages.rb
@@ -18,12 +18,12 @@ FactoryBot.define do
association :wiki, factory: :project_wiki, strategy: :build
initialize_with { new(wiki, page, true) }
- before(:create) do |wiki_page, evaluator|
- wiki_page.attributes = evaluator.attrs.with_indifferent_access
+ before(:create) do |page, evaluator|
+ page.attributes = evaluator.attrs
end
- to_create do |wiki_page|
- wiki_page.create
+ to_create do |page|
+ page.create
end
end
end
diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb
index 8b7fef84dd7..9ec61743a11 100644
--- a/spec/features/projects/features_visibility_spec.rb
+++ b/spec/features/projects/features_visibility_spec.rb
@@ -3,9 +3,8 @@
require 'spec_helper'
describe 'Edit Project Settings' do
- set(:project) { create(:project, :public, :repository) }
-
let(:member) { create(:user) }
+ let!(:project) { create(:project, :public, :repository) }
let!(:issue) { create(:issue, project: project) }
let(:non_member) { create(:user) }
@@ -82,88 +81,85 @@ describe 'Edit Project Settings' do
end
describe 'project features visibility pages' do
- set(:pipeline) { create(:ci_empty_pipeline, project: project) }
- set(:job) { create(:ci_build, pipeline: pipeline) }
-
- where(:method_name, :build_url) do
- [
- [:builds, -> { project_job_path(project, job) }],
- [:issues, -> { project_issues_path(project) }],
- [:wiki, -> { project_wiki_path(project, :home) }],
- [:snippets, -> { project_snippets_path(project) }],
- [:merge_requests, -> { project_merge_requests_path(project) }]
- ]
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
+ let(:job) { create(:ci_build, pipeline: pipeline) }
+
+ let(:tools) do
+ {
+ builds: project_job_path(project, job),
+ issues: project_issues_path(project),
+ wiki: project_wiki_path(project, :home),
+ snippets: project_snippets_path(project),
+ merge_requests: project_merge_requests_path(project)
+ }
end
- with_them do
- let(:url) { build_url.call }
- let(:attr_name) { "#{method_name}_access_level" }
-
- context 'normal user' do
- before do
- project.team.truncate
- sign_in(member)
- end
-
- it 'renders 200 if tool is enabled' do
- project.project_feature.update_attribute(attr_name, ProjectFeature::ENABLED)
+ context 'normal user' do
+ before do
+ sign_in(member)
+ end
+ it 'renders 200 if tool is enabled' do
+ tools.each do |method_name, url|
+ project.project_feature.update_attribute("#{method_name}_access_level", ProjectFeature::ENABLED)
visit url
-
expect(page.status_code).to eq(200)
end
+ end
- it 'renders 404 if feature is disabled' do
- project.project_feature.update_attribute(attr_name, ProjectFeature::DISABLED)
-
+ it 'renders 404 if feature is disabled' do
+ tools.each do |method_name, url|
+ project.project_feature.update_attribute("#{method_name}_access_level", ProjectFeature::DISABLED)
visit url
-
expect(page.status_code).to eq(404)
end
+ end
- it 'renders 404 if feature is enabled only for team members' do
- project.project_feature.update_attribute(attr_name, ProjectFeature::PRIVATE)
+ it 'renders 404 if feature is enabled only for team members' do
+ project.team.truncate
+ tools.each do |method_name, url|
+ project.project_feature.update_attribute("#{method_name}_access_level", ProjectFeature::PRIVATE)
visit url
-
expect(page.status_code).to eq(404)
end
+ end
- it 'renders 200 if user is member of group' do
- group = create(:group)
- project.group = group
- project.save
-
- group.add_owner(member)
+ it 'renders 200 if user is member of group' do
+ group = create(:group)
+ project.group = group
+ project.save
- project.project_feature.update_attribute(attr_name, ProjectFeature::PRIVATE)
+ group.add_owner(member)
+ tools.each do |method_name, url|
+ project.project_feature.update_attribute("#{method_name}_access_level", ProjectFeature::PRIVATE)
visit url
-
expect(page.status_code).to eq(200)
end
end
+ end
- context 'admin user' do
- before do
- non_member.update_attribute(:admin, true)
- project.team.truncate
- sign_in(non_member)
- end
+ context 'admin user' do
+ before do
+ non_member.update_attribute(:admin, true)
+ sign_in(non_member)
+ end
- it 'renders 404 if feature is disabled' do
+ it 'renders 404 if feature is disabled' do
+ tools.each do |method_name, url|
project.project_feature.update_attribute("#{method_name}_access_level", ProjectFeature::DISABLED)
-
visit url
-
expect(page.status_code).to eq(404)
end
+ end
- it 'renders 200 if feature is enabled only for team members' do
- project.project_feature.update_attribute("#{method_name}_access_level", ProjectFeature::PRIVATE)
+ it 'renders 200 if feature is enabled only for team members' do
+ project.team.truncate
+ tools.each do |method_name, url|
+ project.project_feature.update_attribute("#{method_name}_access_level", ProjectFeature::PRIVATE)
visit url
-
expect(page.status_code).to eq(200)
end
end
diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb
index a56b3e4955a..5c6b04a7141 100644
--- a/spec/features/projects/wiki/markdown_preview_spec.rb
+++ b/spec/features/projects/wiki/markdown_preview_spec.rb
@@ -4,54 +4,164 @@ require 'spec_helper'
describe 'Projects > Wiki > User previews markdown changes', :js do
set(:user) { create(:user) }
- set(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- let(:project_wiki) { ProjectWiki.new(project, user) }
+ let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
+ let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: '[some link](other-page)' }) }
+ let(:wiki_content) do
+ <<-HEREDOC
+[regular link](regular)
+[relative link 1](../relative)
+[relative link 2](./relative)
+[relative link 3](./e/f/relative)
+[spaced link](title with spaces)
+ HEREDOC
+ end
before do
project.add_maintainer(user)
+
sign_in(user)
- init_home!
end
- def init_home!
- create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: '[some link](other-page)' })
- end
+ context "while creating a new wiki page" do
+ context "when there are no spaces or hyphens in the page name" do
+ it "rewrites relative links as expected" do
+ create_wiki_page('a/b/c/d', content: wiki_content)
- def fill_in_content!
- page.within '.wiki-form' do
- fill_in :wiki_page_content, with: wiki_content
+ expect(page).to have_content("regular link")
+
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
+ end
end
- end
- def show_preview!
- page.within '.wiki-form' do
- click_on 'Preview'
+ context "when there are spaces in the page name" do
+ it "rewrites relative links as expected" do
+ create_wiki_page('a page/b page/c page/d page', content: wiki_content)
+
+ expect(page).to have_content("regular link")
+
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
+ end
end
- end
- context 'when writing a new page' do
- let(:new_wiki_path) { 'a/b/c/d' }
- let(:wiki_content) { 'Some [awesome wiki](content)' }
+ context "when there are hyphens in the page name" do
+ it "rewrites relative links as expected" do
+ create_wiki_page('a-page/b-page/c-page/d-page', content: wiki_content)
- it 'can show a preview of markdown content' do
- visit project_wiki_pages_new_path(project, id: new_wiki_path)
- fill_in_content!
- show_preview!
+ expect(page).to have_content("regular link")
- expect(page).to have_link('awesome wiki')
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
+ end
end
end
- context 'when editing an existing page' do
- let(:wiki_content) { 'Some [bemusing](content)' }
- let(:wiki_page) { create(:wiki_page, wiki: project_wiki) }
+ context "while editing a wiki page" do
+ context "when there are no spaces or hyphens in the page name" do
+ it "rewrites relative links as expected" do
+ create_wiki_page('a/b/c/d')
+ click_link 'Edit'
+
+ fill_in :wiki_content, with: wiki_content
+ click_on "Preview"
+
+ expect(page).to have_content("regular link")
+
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
+ end
+ end
+
+ context "when there are spaces in the page name" do
+ it "rewrites relative links as expected" do
+ create_wiki_page('a page/b page/c page/d page')
+ click_link 'Edit'
+
+ fill_in :wiki_content, with: wiki_content
+ click_on "Preview"
+
+ expect(page).to have_content("regular link")
+
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
+ end
+ end
+
+ context "when there are hyphens in the page name" do
+ it "rewrites relative links as expected" do
+ create_wiki_page('a-page/b-page/c-page/d-page')
+ click_link 'Edit'
+
+ fill_in :wiki_content, with: wiki_content
+ click_on "Preview"
- it 'can show a preview of markdown content, when writing' do
- visit project_wiki_edit_path(project, wiki_page)
- fill_in_content!
- show_preview!
+ expect(page).to have_content("regular link")
- expect(page).to have_link('bemusing')
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
+ end
end
+
+ context 'when rendering the preview' do
+ it 'renders content with CommonMark' do
+ create_wiki_page('a-page/b-page/c-page/common-mark')
+ click_link 'Edit'
+
+ fill_in :wiki_content, with: "1. one\n - sublist\n"
+ click_on "Preview"
+
+ # the above generates two separate lists (not embedded) in CommonMark
+ expect(page).to have_content("sublist")
+ expect(page).not_to have_xpath("//ol//li//ul")
+ end
+ end
+ end
+
+ it "does not linkify double brackets inside code blocks as expected" do
+ wiki_content = <<-HEREDOC
+ `[[do_not_linkify]]`
+ ```
+ [[also_do_not_linkify]]
+ ```
+ HEREDOC
+
+ create_wiki_page('linkify_test', wiki_content)
+
+ expect(page).to have_content("do_not_linkify")
+
+ expect(page.html).to include('[[do_not_linkify]]')
+ expect(page.html).to include('[[also_do_not_linkify]]')
+ end
+
+ private
+
+ def create_wiki_page(path, content = 'content')
+ visit project_wiki_path(project, wiki_page)
+
+ click_link 'New page'
+
+ fill_in :wiki_title, with: path
+ fill_in :wiki_content, with: content
+
+ click_button 'Create page'
end
end
diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb
index 6b651ccb67a..56d0518015d 100644
--- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb
@@ -3,15 +3,9 @@
require "spec_helper"
describe "User creates wiki page" do
- include CapybaraHelpers
- include WikiHelpers
-
- set(:user) { create(:user) }
-
- let(:project) { create(:project) }
+ let(:user) { create(:user) }
let(:wiki) { ProjectWiki.new(project, user) }
- let(:new_page) { WikiPage.new(wiki) }
- let(:message_field) { form_field_name(new_page, :message) }
+ let(:project) { create(:project) }
before do
project.add_maintainer(user)
@@ -19,76 +13,36 @@ describe "User creates wiki page" do
sign_in(user)
end
- def start_writing(page_path)
- click_link("New page")
- fill_in(:wiki_page_title, with: page_path)
- end
-
- def create_page(attrs = {})
- page.within(".wiki-form") do
- attrs.each do |k, v|
- fill_in("wiki_page_#{k}".to_sym, with: v)
- end
- end
- click_on("Create page")
- end
-
- shared_examples 'updates commit message' do
- describe 'commit message', :js do
- it "has `Create home` as a commit message" do
- wait_for_requests
-
- expect(page).to have_field(message_field, with: "Create home")
- end
- end
- end
-
context "when wiki is empty" do
before do
visit(project_wikis_path(project))
click_link "Create your first page"
- find('.wiki-form')
end
context "in a user namespace" do
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- let(:wiki_page_content) { '' }
it "shows validation error message" do
- create_page
-
- expect(page)
- .to have_content("The form contains the following error:")
- .and have_content("Content can't be blank")
- .and have_css('.wiki-form')
- .and have_css('.qa-create-page-button')
- end
-
- it 'offers to create pages that do not yet exist' do
- create_page(content: "[link test](test)")
+ page.within(".wiki-form") do
+ fill_in(:wiki_content, with: "")
- expect(page)
- .to have_content("Home")
- .and have_content("link test")
+ click_on("Create page")
+ end
- click_link("link test")
+ expect(page).to have_content("The form contains the following error:").and have_content("Content can't be blank")
- expect(page).to have_content("Create New Page")
- end
+ page.within(".wiki-form") do
+ fill_in(:wiki_content, with: "[link test](test)")
- it "has a link to the parent directory in the pages sidebar" do
- wiki_full_path = "one/two/three-test"
- create_page(title: wiki_full_path, content: 'wiki content')
+ click_on("Create page")
+ end
- wiki_page = wiki.find_page(wiki_full_path)
- expect(wiki_page).to be_present
- dir = wiki.find_dir(wiki_page.directory)
- expect(dir).to be_present
+ expect(page).to have_content("Home").and have_content("link test")
- expect(current_path).to include(wiki_full_path)
+ click_link("link test")
- expect(page).to have_link(dir.slug, href: project_wiki_dir_path(project, dir))
+ expect(page).to have_content("Create New Page")
end
it "shows non-escaped link in the pages list", :quarantine do
@@ -104,17 +58,19 @@ describe "User creates wiki page" do
expect(page).to have_xpath("//a[@href='/#{project.full_path}/wikis/one/two/three-test']")
end
- it_behaves_like 'updates commit message'
+ it "has `Create home` as a commit message", :js do
+ wait_for_requests
+
+ expect(page).to have_field("wiki[message]", with: "Create home")
+ end
it "creates a page from the home page" do
- page_content = <<~WIKI_CONTENT
- [test](test)
- [GitLab API doc](api)
- [Rake tasks](raketasks)
- # Wiki header
- WIKI_CONTENT
+ fill_in(:wiki_content, with: "[test](test)\n[GitLab API doc](api)\n[Rake tasks](raketasks)\n# Wiki header\n")
+ fill_in(:wiki_message, with: "Adding links to wiki")
- create_page(content: page_content, message: "Adding links to wiki")
+ page.within(".wiki-form") do
+ click_button("Create page")
+ end
expect(current_path).to eq(project_wiki_path(project, "home"))
expect(page).to have_content("test GitLab API doc Rake tasks Wiki header")
@@ -155,7 +111,7 @@ describe "User creates wiki page" do
end
end
- it "creates ASCIIdoc wiki with LaTeX blocks", :js do
+ it "creates ASCII wiki with LaTeX blocks", :js do
stub_application_setting(plantuml_url: "http://localhost", plantuml_enabled: true)
ascii_content = <<~MD
@@ -176,25 +132,37 @@ describe "User creates wiki page" do
stem:[2+2] is 4
MD
- find("#wiki_page_format option[value=asciidoc]").select_option
+ find("#wiki_format option[value=asciidoc]").select_option
+
+ fill_in(:wiki_content, with: ascii_content)
- create_page(content: ascii_content)
+ page.within(".wiki-form") do
+ click_button("Create page")
+ end
page.within ".md" do
expect(page).to have_selector(".katex", count: 3).and have_content("2+2 is 4")
end
end
- it_behaves_like 'wiki file attachments'
+ it_behaves_like 'wiki file attachments', :quarantine
end
- context "in a group namespace" do
+ context "in a group namespace", :js do
let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) }
- it_behaves_like 'updates commit message'
+ it "has `Create home` as a commit message" do
+ wait_for_requests
- it "creates a page from the home page" do
- create_page(content: "My awesome wiki!")
+ expect(page).to have_field("wiki[message]", with: "Create home")
+ end
+
+ it "creates a page from the home page", :quarantine do
+ page.within(".wiki-form") do
+ fill_in(:wiki_content, with: "My awesome wiki!")
+
+ click_button("Create page")
+ end
expect(page).to have_content("Home")
.and have_content("Last edited by #{user.name}")
@@ -210,37 +178,76 @@ describe "User creates wiki page" do
visit(project_wikis_path(project))
end
- shared_examples 'creates page by slug' do |slug, unslug|
- it "creates #{slug}" do
- start_writing(slug)
+ context "in a user namespace" do
+ let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- # Commit message field should have correct value.
- expect(page).to have_field(message_field, with: "Create #{unslug}")
+ context "via the `new wiki page` page" do
+ it "creates a page with a single word" do
+ click_link("New page")
- create_page(content: "My awesome wiki!")
+ page.within(".wiki-form") do
+ fill_in(:wiki_title, with: "foo")
+ fill_in(:wiki_content, with: "My awesome wiki!")
+ end
- expect(page).to have_content(unslug)
- .and have_content("Last edited by #{user.name}")
- .and have_content("My awesome wiki!")
- end
- end
+ # Commit message field should have correct value.
+ expect(page).to have_field("wiki[message]", with: "Create foo")
- context "in a user namespace" do
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
+ click_button("Create page")
- context "via the `new wiki page` page" do
- include_examples 'creates page by slug', 'foo', 'foo'
- include_examples 'creates page by slug', 'Spaces in the name', 'Spaces in the name'
- include_examples 'creates page by slug', 'Hyphens-in-the-name', 'Hyphens in the name'
+ expect(page).to have_content("foo")
+ .and have_content("Last edited by #{user.name}")
+ .and have_content("My awesome wiki!")
+ end
+
+ it "creates a page with spaces in the name" do
+ click_link("New page")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_title, with: "Spaces in the name")
+ fill_in(:wiki_content, with: "My awesome wiki!")
+ end
+
+ # Commit message field should have correct value.
+ expect(page).to have_field("wiki[message]", with: "Create Spaces in the name")
+
+ click_button("Create page")
+
+ expect(page).to have_content("Spaces in the name")
+ .and have_content("Last edited by #{user.name}")
+ .and have_content("My awesome wiki!")
+ end
+
+ it "creates a page with hyphens in the name" do
+ click_link("New page")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_title, with: "hyphens-in-the-name")
+ fill_in(:wiki_content, with: "My awesome wiki!")
+ end
+
+ # Commit message field should have correct value.
+ expect(page).to have_field("wiki[message]", with: "Create hyphens in the name")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_content, with: "My awesome wiki!")
+
+ click_button("Create page")
+ end
+
+ expect(page).to have_content("hyphens in the name")
+ .and have_content("Last edited by #{user.name}")
+ .and have_content("My awesome wiki!")
+ end
end
it "shows the emoji autocompletion dropdown" do
- start_writing('text-autocomplete')
+ click_link("New page")
page.within(".wiki-form") do
- find("#wiki_page_content").native.send_keys("")
+ find("#wiki_content").native.send_keys("")
- fill_in(:wiki_page_content, with: ":")
+ fill_in(:wiki_content, with: ":")
end
expect(page).to have_selector(".atwho-view")
@@ -251,9 +258,23 @@ describe "User creates wiki page" do
let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) }
context "via the `new wiki page` page" do
- include_examples 'creates page by slug', 'foo', 'foo'
- include_examples 'creates page by slug', 'Spaces in the name', 'Spaces in the name'
- include_examples 'creates page by slug', 'Hyphens-in-the-name', 'Hyphens in the name'
+ it "creates a page" do
+ click_link("New page")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_title, with: "foo")
+ fill_in(:wiki_content, with: "My awesome wiki!")
+ end
+
+ # Commit message field should have correct value.
+ expect(page).to have_field("wiki[message]", with: "Create foo")
+
+ click_button("Create page")
+
+ expect(page).to have_content("foo")
+ .and have_content("Last edited by #{user.name}")
+ .and have_content("My awesome wiki!")
+ end
end
end
end
diff --git a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb b/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb
index 9b9d3100bf5..38e5e292064 100644
--- a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb
@@ -6,7 +6,6 @@ describe 'User deletes wiki page', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki) }
- let(:project_wiki) { ProjectWiki.new(project, user) }
before do
sign_in(user)
@@ -19,6 +18,5 @@ describe 'User deletes wiki page', :js do
find('.modal-footer .btn-danger').click
expect(page).to have_content('Page was successfully deleted')
- expect(project_wiki.find_page(wiki_page.slug)).to be nil
end
end
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 5ab44e83f73..3f3711f9eb8 100644
--- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
@@ -10,13 +10,6 @@ describe 'User updates wiki page' do
sign_in(user)
end
- def create_page(attrs = {})
- page.within('.wiki-form') do
- attrs.each { |k, v| fill_in("wiki_page_#{k}".to_sym, with: v) }
- click_on('Create page')
- end
- end
-
context 'when wiki is empty' do
before do
visit(project_wikis_path(project))
@@ -35,7 +28,12 @@ describe 'User updates wiki page' do
end
it 'updates a page that has a path', :js do
- create_page(title: 'one/two/three-test', content: 'wiki content')
+ fill_in(:wiki_title, with: 'one/two/three-test')
+
+ page.within '.wiki-form' do
+ fill_in(:wiki_content, with: 'wiki content')
+ click_on('Create page')
+ end
expect(current_path).to include('one/two/three-test')
expect(find('.wiki-pages')).to have_content('three')
@@ -74,9 +72,9 @@ describe 'User updates wiki page' do
it 'updates a page', :js do
# Commit message field should have correct value.
- expect(page).to have_field('wiki_page[message]', with: 'Update home')
+ expect(page).to have_field('wiki[message]', with: 'Update home')
- fill_in(:wiki_page_content, with: 'My awesome wiki!')
+ fill_in(:wiki_content, with: 'My awesome wiki!')
click_button('Save changes')
expect(page).to have_content('Home')
@@ -85,31 +83,31 @@ describe 'User updates wiki page' do
end
it 'updates the commit message as the title is changed', :js do
- fill_in(:wiki_page_title, with: 'Wiki title')
+ fill_in(:wiki_title, with: 'Wiki title')
- expect(page).to have_field('wiki_page[message]', with: 'Update Wiki title')
+ expect(page).to have_field('wiki[message]', with: 'Update Wiki title')
end
it 'does not allow XSS', :js do
- fill_in(:wiki_page_title, with: '<script>')
+ fill_in(:wiki_title, with: '<script>')
- expect(page).to have_field('wiki_page[message]', with: 'Update &lt;script&gt;')
+ expect(page).to have_field('wiki[message]', with: 'Update &lt;script&gt;')
end
it 'shows a validation error message' do
- fill_in(:wiki_page_content, with: '')
+ fill_in(:wiki_content, with: '')
click_button('Save changes')
expect(page).to have_selector('.wiki-form')
expect(page).to have_content('Edit Page')
expect(page).to have_content('The form contains the following error:')
expect(page).to have_content("Content can't be blank")
- expect(find('textarea#wiki_page_content').value).to eq('')
+ expect(find('textarea#wiki_content').value).to eq('')
end
it 'shows the emoji autocompletion dropdown', :js do
- find('#wiki_page_content').native.send_keys('')
- fill_in(:wiki_page_content, with: ':')
+ find('#wiki_content').native.send_keys('')
+ fill_in(:wiki_content, with: ':')
expect(page).to have_selector('.atwho-view')
end
@@ -145,9 +143,9 @@ describe 'User updates wiki page' do
it 'updates a page', :js do
# Commit message field should have correct value.
- expect(page).to have_field('wiki_page[message]', with: 'Update home')
+ expect(page).to have_field('wiki[message]', with: 'Update home')
- fill_in(:wiki_page_content, with: 'My awesome wiki!')
+ fill_in(:wiki_content, with: 'My awesome wiki!')
click_button('Save changes')
@@ -171,43 +169,50 @@ describe 'User updates wiki page' do
visit(project_wiki_edit_path(project, wiki_page))
end
- def edit_title!(title)
- fill_in(:wiki_page_title, with: title)
+ it 'moves the page to the root folder' do
+ fill_in(:wiki_title, with: "/#{page_name}")
click_button('Save changes')
- end
-
- it 'moves the page to the root folder' do
- edit_title!("/#{page_name}")
expect(current_path).to eq(project_wiki_path(project, page_name))
end
it 'moves the page to other dir' do
- new_page_path = "baz/quux/#{page_name}"
- edit_title!(new_page_path)
+ 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_path))
+ 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)
- edit_title!(page_name)
+
+ 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_path = "quux/baz/new_page_name"
- edit_title!(new_page_path)
+ new_page_dir = "foo1/bar1/new_page_name"
+
+ fill_in(:wiki_title, with: new_page_dir)
- expect(current_path).to eq(project_wiki_path(project, new_page_path))
+ 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'
- edit_title!("/#{new_name}")
+ fill_in(:wiki_title, with: "/#{new_name}")
+
+ click_button('Save changes')
expect(current_path).to eq(project_wiki_path(project, new_name))
end
@@ -215,7 +220,9 @@ describe 'User updates wiki page' do
it 'squishes the title before creating the page' do
new_page_dir = " foo1 / bar1 / #{page_name} "
- edit_title!(new_page_dir)
+ 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
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 af8f86106d9..77e725e7f11 100644
--- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_views_wiki_page_spec.rb
@@ -8,11 +8,10 @@ describe 'User views a wiki page' do
let(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:path) { 'image.png' }
- let(:wiki_content) { "Look at this [image](#{path})\n\n ![alt text](#{path})" }
let(:wiki_page) do
create(:wiki_page,
wiki: project.wiki,
- attrs: { title: 'home', content: wiki_content })
+ attrs: { title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})" })
end
before do
@@ -20,18 +19,17 @@ describe 'User views a wiki page' do
sign_in(user)
end
- def create_page(attrs = {})
- page.within('.wiki-form') do
- attrs.each { |k, v| fill_in("wiki_page_#{k}".to_sym, with: v) }
- click_on('Create page')
- end
- end
-
context 'when wiki is empty' do
before do
visit(project_wikis_path(project))
click_link "Create your first page"
- create_page(title: 'one/two/three-test', content: 'wiki content')
+
+ fill_in(:wiki_title, with: 'one/two/three-test')
+
+ page.within('.wiki-form') do
+ fill_in(:wiki_content, with: 'wiki content')
+ click_on('Create page')
+ end
end
it 'shows the history of a page that has a path', :js do
@@ -85,27 +83,24 @@ describe 'User views a wiki page' do
context 'shows a file stored in a page' do
let(:path) { upload_file_to_wiki(project, user, 'dk.png') }
- let(:image_path) { project_wiki_path(project, path) }
it do
- expect(page).to have_xpath("//img[@data-src='#{image_path}']")
- expect(page).to have_link('image', href: "#{image_path}")
+ expect(page).to have_xpath("//img[@data-src='#{project.wiki.wiki_base_path}/#{path}']")
+ expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/#{path}")
click_on('image')
- expect(current_path).to match(path)
+ expect(current_path).to match("wikis/#{path}")
expect(page).not_to have_xpath('/html') # Page should render the image which means there is no html involved
end
end
it 'shows the creation page if file does not exist' do
- href = project_wiki_path(project, path)
-
- expect(page).to have_link('image', href: href)
+ expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/#{path}")
click_on('image')
- expect(current_path).to match(href)
+ expect(current_path).to match("wikis/#{path}")
expect(page).to have_content('Create New Page')
end
end
diff --git a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb
index adb59c891c6..6740df1d4ed 100644
--- a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb
+++ b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb
@@ -7,7 +7,6 @@ describe 'User views wiki pages' do
let(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- let(:project_wiki) { ProjectWiki.new(project, user) }
let!(:wiki_page1) do
create(:wiki_page, wiki: project.wiki, attrs: { title: '3 home', content: '3' })
@@ -18,182 +17,73 @@ describe 'User views wiki pages' do
let!(:wiki_page3) do
create(:wiki_page, wiki: project.wiki, attrs: { title: '2 home', content: '2' })
end
- let!(:wiki_page4) do
- create(:wiki_page, wiki: project.wiki, attrs: { title: 'sub-folder/0', content: 'a' })
- end
- let!(:wiki_page5) do
- create(:wiki_page, wiki: project.wiki, attrs: { title: 'sub-folder/b', content: 'b' })
- end
-
- let(:page_link_selector) { 'a' }
let(:pages) do
- page.all(".wiki-pages-list li #{page_link_selector}")
+ page.find('.wiki-pages-list').all('li').map { |li| li.find('a') }
end
- let(:wikis_allow_change_nesting) { false }
before do
- stub_feature_flags(wikis_allow_change_nesting: wikis_allow_change_nesting)
project.add_maintainer(user)
sign_in(user)
visit(project_wikis_pages_path(project))
end
- def sort_desc!
- page.within('.wiki-sort-dropdown') do
- page.find('.qa-reverse-sort').click
- end
- end
-
- def sort_by_created_at!
- page.within('.wiki-sort-dropdown') do
- click_button('Title')
- click_link('Created date')
- end
- end
-
- shared_examples 'correctly_sorted_pages' do
- it 'has pages displayed in correct order' do
- displayed_texts = pages.map(&:text)
- expect(displayed_texts).to eq expected_sequence.map(&:title)
- end
- end
-
context 'ordered by title' do
- let(:sub_folder) { project_wiki.find_dir('sub-folder') }
+ let(:pages_ordered_by_title) { [wiki_page2, wiki_page3, wiki_page1] }
- context 'default display settings' do
- context 'asc' do
- let(:expected_sequence) { [wiki_page2, wiki_page3, wiki_page1, sub_folder] }
-
- it_behaves_like 'correctly_sorted_pages'
- end
-
- context 'desc' do
- before do
- sort_desc!
+ context 'asc' do
+ it 'pages are displayed in direct order' do
+ pages.each.with_index do |page_title, index|
+ expect(page_title.text).to eq(pages_ordered_by_title[index].title)
end
-
- let(:expected_sequence) { [sub_folder, wiki_page1, wiki_page3, wiki_page2] }
-
- it_behaves_like 'correctly_sorted_pages'
- end
- end
-
- context 'changing nesting is disabled' do
- let(:wikis_allow_change_nesting) { false }
-
- it 'does not display a nesting controller' do
- expect(page).not_to have_css('.wiki-nesting-dropdown')
end
end
- context 'changing nesting is enabled' do
- let(:wikis_allow_change_nesting) { true }
-
- it 'displays a nesting controller' do
- expect(page).to have_css('.wiki-nesting-dropdown')
- end
-
- context 'tree' do
- before do
- page.within('.wiki-nesting-dropdown') do
- click_link 'Show folder contents'
- end
- end
-
- context 'asc' do
- let(:expected_sequence) { [wiki_page2, wiki_page3, wiki_page1, sub_folder, wiki_page4, wiki_page5] }
-
- it_behaves_like 'correctly_sorted_pages'
- end
-
- context 'desc' do
- before do
- sort_desc!
- end
-
- let(:expected_sequence) { [sub_folder, wiki_page5, wiki_page4, wiki_page1, wiki_page3, wiki_page2] }
-
- it_behaves_like 'correctly_sorted_pages'
- end
- end
-
- context 'nested' do
- before do
- page.within('.wiki-nesting-dropdown') do
- click_link 'Hide folder contents'
- end
- end
-
- context 'asc' do
- let(:expected_sequence) { [wiki_page2, wiki_page3, wiki_page1, sub_folder] }
-
- it_behaves_like 'correctly_sorted_pages'
- end
-
- context 'desc' do
- before do
- sort_desc!
- end
-
- let(:expected_sequence) { [sub_folder, wiki_page1, wiki_page3, wiki_page2] }
-
- it_behaves_like 'correctly_sorted_pages'
+ context 'desc' do
+ before do
+ page.within('.wiki-sort-dropdown') do
+ page.find('.rspec-reverse-sort').click
end
end
- context 'flat' do
- before do
- page.within('.wiki-nesting-dropdown') do
- click_link 'Show files separately'
- end
- end
-
- let(:page_link_selector) { 'a.wiki-page-title' }
-
- context 'asc' do
- let(:expected_sequence) { [wiki_page2, wiki_page3, wiki_page1, wiki_page4, wiki_page5] }
-
- it_behaves_like 'correctly_sorted_pages'
- end
-
- context 'desc' do
- before do
- sort_desc!
- end
-
- let(:expected_sequence) { [wiki_page5, wiki_page4, wiki_page1, wiki_page3, wiki_page2] }
-
- it_behaves_like 'correctly_sorted_pages'
+ it 'pages are displayed in reversed order' do
+ pages.reverse_each.with_index do |page_title, index|
+ expect(page_title.text).to eq(pages_ordered_by_title[index].title)
end
end
end
end
context 'ordered by created_at' do
- let(:pages_ordered_by_created_at) { [wiki_page1, wiki_page2, wiki_page3, wiki_page4, wiki_page5] }
+ let(:pages_ordered_by_created_at) { [wiki_page1, wiki_page2, wiki_page3] }
before do
- sort_by_created_at!
+ page.within('.wiki-sort-dropdown') do
+ click_button('Title')
+ click_link('Created date')
+ end
end
- let(:page_link_selector) { 'a.wiki-page-title' }
-
context 'asc' do
- let(:expected_sequence) { [wiki_page1, wiki_page2, wiki_page3, wiki_page4, wiki_page5] }
-
- it_behaves_like 'correctly_sorted_pages'
+ it 'pages are displayed in direct order' do
+ pages.each.with_index do |page_title, index|
+ expect(page_title.text).to eq(pages_ordered_by_created_at[index].title)
+ end
+ end
end
context 'desc' do
before do
- sort_desc!
+ page.within('.wiki-sort-dropdown') do
+ page.find('.rspec-reverse-sort').click
+ end
end
- let(:expected_sequence) { [wiki_page5, wiki_page4, wiki_page3, wiki_page2, wiki_page1] }
-
- it_behaves_like 'correctly_sorted_pages'
+ it 'pages are displayed in reversed order' do
+ pages.reverse_each.with_index do |page_title, index|
+ expect(page_title.text).to eq(pages_ordered_by_created_at[index].title)
+ end
+ end
end
end
end
diff --git a/spec/frontend/wikis_spec.js b/spec/frontend/wikis_spec.js
index a2b68bf866e..b2475488d97 100644
--- a/spec/frontend/wikis_spec.js
+++ b/spec/frontend/wikis_spec.js
@@ -3,27 +3,27 @@ import { setHTMLFixture } from './helpers/fixtures';
describe('Wikis', () => {
describe('setting the commit message when the title changes', () => {
+ const editFormHtmlFixture = args => `<form class="wiki-form ${
+ args.newPage ? 'js-new-wiki-page' : ''
+ }">
+ <input type="text" id="wiki_title" value="My title" />
+ <input type="text" id="wiki_message" />
+ </form>`;
+
let wikis;
let titleInput;
let messageInput;
- const CREATE = true;
- const UPDATE = false;
- const editFormHtmlFixture = newPage =>
- `<form class="wiki-form ${newPage ? 'js-new-wiki-page' : ''}">
- <input type="text" id="wiki_page_title" value="My title" />
- <input type="text" id="wiki_page_message" />
- </form>`;
+ describe('when the wiki page is being created', () => {
+ const formHtmlFixture = editFormHtmlFixture({ newPage: true });
- const init = newPage => {
- setHTMLFixture(editFormHtmlFixture(newPage));
- titleInput = document.getElementById('wiki_page_title');
- messageInput = document.getElementById('wiki_page_message');
- wikis = new Wikis();
- };
+ beforeEach(() => {
+ setHTMLFixture(formHtmlFixture);
- describe('when the wiki page is being created', () => {
- beforeEach(() => init(CREATE));
+ titleInput = document.getElementById('wiki_title');
+ messageInput = document.getElementById('wiki_message');
+ wikis = new Wikis();
+ });
it('binds an event listener to the title input', () => {
wikis.handleWikiTitleChange = jest.fn();
@@ -51,7 +51,15 @@ describe('Wikis', () => {
});
describe('when the wiki page is being updated', () => {
- beforeEach(() => init(UPDATE));
+ const formHtmlFixture = editFormHtmlFixture({ newPage: false });
+
+ beforeEach(() => {
+ setHTMLFixture(formHtmlFixture);
+
+ titleInput = document.getElementById('wiki_title');
+ messageInput = document.getElementById('wiki_message');
+ wikis = new Wikis();
+ });
it('sets the commit message when title changes, prefixing with "Update"', () => {
titleInput.value = 'My title';
diff --git a/spec/helpers/wiki_helper_spec.rb b/spec/helpers/wiki_helper_spec.rb
index 4310e4bd22c..bcc2bd71da1 100644
--- a/spec/helpers/wiki_helper_spec.rb
+++ b/spec/helpers/wiki_helper_spec.rb
@@ -23,13 +23,8 @@ describe WikiHelper do
describe '#wiki_sort_controls' do
let(:project) { create(:project) }
- let(:classes) { described_class::WIKI_SORT_CSS_CLASSES }
-
- subject(:wiki_link) do
- helper.wiki_sort_controls(sort: sort, direction: direction) do |opts|
- project_wikis_pages_path(project, opts)
- end
- end
+ let(:wiki_link) { helper.wiki_sort_controls(project, sort, direction) }
+ let(:classes) { "btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort" }
def expected_link(sort, direction, icon_class)
path = "/#{project.full_path}/wikis/pages?direction=#{direction}&sort=#{sort}"
@@ -67,18 +62,6 @@ describe WikiHelper do
end
end
- describe '#wiki_show_children_icon' do
- ProjectWiki::NESTINGS.each do |nesting|
- context "When the nesting parameter is `#{nesting}`" do
- let(:element) { helper.wiki_show_children_icon(nesting) }
-
- it 'produces something that contains an SVG' do
- expect(element).to match(/svg/)
- end
- end
- end
- end
-
describe '#wiki_sort_title' do
it 'returns a title corresponding to a key' do
expect(helper.wiki_sort_title('created_at')).to eq('Created date')
diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
index 7a83dc3ec1d..4587bd85939 100644
--- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
@@ -11,10 +11,6 @@ describe Banzai::Filter::WikiLinkFilter do
let(:wiki) { ProjectWiki.new(project, user) }
let(:repository_upload_folder) { Wikis::CreateAttachmentService::ATTACHMENT_PATH }
- def upload_href(file_name)
- ::File.join(wiki.wiki_page_path, repository_upload_folder, file_name)
- end
-
it "doesn't rewrite absolute links" do
filtered_link = filter("<a href='http://example.com:8000/'>Link</a>", project_wiki: wiki).children[0]
@@ -32,12 +28,12 @@ describe Banzai::Filter::WikiLinkFilter do
it 'rewrites links' do
filtered_link = filter("<a href='#{repository_upload_folder}/a.test'>Link</a>", project_wiki: wiki).children[0]
- expect(filtered_link.attribute('href').value).to eq(upload_href "a.test")
+ expect(filtered_link.attribute('href').value).to eq("#{wiki.wiki_base_path}/#{repository_upload_folder}/a.test")
end
end
context 'with "img" html tag' do
- let(:path) { upload_href "a.jpg" }
+ let(:path) { "#{wiki.wiki_base_path}/#{repository_upload_folder}/a.jpg" }
context 'inside an "a" html tag' do
it 'rewrites links' do
@@ -61,7 +57,7 @@ describe Banzai::Filter::WikiLinkFilter do
it 'rewrites links' do
filtered_link = filter("<video src='#{repository_upload_folder}/a.mp4'></video>", project_wiki: wiki).children[0]
- expect(filtered_link.attribute('src').value).to eq(upload_href "a.mp4")
+ expect(filtered_link.attribute('src').value).to eq("#{wiki.wiki_base_path}/#{repository_upload_folder}/a.mp4")
end
end
@@ -69,8 +65,7 @@ describe Banzai::Filter::WikiLinkFilter do
it 'rewrites links' do
filtered_link = filter("<audio src='#{repository_upload_folder}/a.wav'></audio>", project_wiki: wiki).children[0]
- # expect(filtered_link.attribute('src').value).to eq("#{wiki.wiki_base_path}/#{repository_upload_folder}/a.wav")
- expect(filtered_link.attribute('src').value).to eq(upload_href "a.wav")
+ expect(filtered_link.attribute('src').value).to eq("#{wiki.wiki_base_path}/#{repository_upload_folder}/a.wav")
end
end
end
diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
index 7f60106cdca..26f2b0b0acf 100644
--- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
@@ -3,12 +3,6 @@
require 'spec_helper'
describe Banzai::Pipeline::WikiPipeline do
- let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") }
- let_it_be(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) }
- let_it_be(:project_wiki) { ProjectWiki.new(project, double(:user)) }
- let_it_be(:page) { build(:wiki_page, wiki: project_wiki, page: OpenStruct.new(url_path: 'nested/twice/start-page')) }
- let(:prefix) { project_wiki.wiki_page_path }
-
describe 'TableOfContents' do
it 'replaces the tag with the TableOfContentsFilter result' do
markdown = <<-MD.strip_heredoc
@@ -60,138 +54,132 @@ describe Banzai::Pipeline::WikiPipeline do
end
describe "Links" do
- shared_examples 'a correct link rewrite' do
- it 'rewrites links correctly' do
- output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
-
- expect(output).to include("href=\"#{page_href}\"")
- end
- end
-
- shared_examples 'link examples' do |test_name|
- let(:page_href) { "#{prefix}/#{expected_page_path}" }
-
- context "when GitLab is hosted at a #{test_name} URL" do
+ let(:namespace) { create(:namespace, name: "wiki_link_ns") }
+ let(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) }
+ let(:project_wiki) { ProjectWiki.new(project, double(:user)) }
+ let(:page) { build(:wiki_page, wiki: project_wiki, page: OpenStruct.new(url_path: 'nested/twice/start-page')) }
+
+ { "when GitLab is hosted at a root URL" => '/',
+ "when GitLab is hosted at a relative URL" => '/nested/relative/gitlab' }.each do |test_name, relative_url_root|
+ context test_name do
before do
allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return(relative_url_root)
end
describe "linking to pages within the wiki" do
- let(:markdown) { "[Page](#{nesting}page#{extension})" }
-
context "when creating hierarchical links to the current directory" do
- let(:nesting) { './' }
- context 'non file links' do
- let(:extension) { '' }
- let(:expected_page_path) { 'nested/twice/page' }
- it_behaves_like 'a correct link rewrite'
+ it "rewrites non-file links to be at the scope of the current directory" do
+ markdown = "[Page](./page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page\"")
end
- context 'file-like links' do
- let(:extension) { '.md' }
- let(:expected_page_path) { 'nested/twice/page.md' }
- it_behaves_like 'a correct link rewrite'
+ it "rewrites file links to be at the scope of the current directory" do
+ markdown = "[Link to Page](./page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
end
end
context "when creating hierarchical links to the parent directory" do
- let(:nesting) { '../' }
- context "non file links" do
- let(:extension) { '' }
- let(:expected_page_path) { 'nested/page' }
- it_behaves_like 'a correct link rewrite'
+ it "rewrites non-file links to be at the scope of the parent directory" do
+ markdown = "[Link to Page](../page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/page\"")
end
- context "file-like links" do
- let(:extension) { '.md' }
- let(:expected_page_path) { 'nested/page.md' }
- it_behaves_like 'a correct link rewrite'
+ it "rewrites file links to be at the scope of the parent directory" do
+ markdown = "[Link to Page](../page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/page.md\"")
end
end
context "when creating hierarchical links to a sub-directory" do
- let(:nesting) { './subdirectory/' }
+ it "rewrites non-file links to be at the scope of the sub-directory" do
+ markdown = "[Link to Page](./subdirectory/page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
- context "non file links" do
- let(:extension) { '' }
- let(:expected_page_path) { 'nested/twice/subdirectory/page' }
- it_behaves_like 'a correct link rewrite'
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/subdirectory/page\"")
end
- context 'file-like links' do
- let(:extension) { '.md' }
- let(:expected_page_path) { 'nested/twice/subdirectory/page.md' }
- it_behaves_like 'a correct link rewrite'
+ it "rewrites file links to be at the scope of the sub-directory" do
+ markdown = "[Link to Page](./subdirectory/page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/subdirectory/page.md\"")
end
end
describe "when creating non-hierarchical links" do
- let(:nesting) { '' }
+ it 'rewrites non-file links to be at the scope of the wiki root' do
+ markdown = "[Link to Page](page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
- context 'non-file links' do
- let(:extension) { '' }
- let(:expected_page_path) { 'page' }
- it_behaves_like 'a correct link rewrite'
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page\"")
end
- context 'non-file links (with spaces)' do
- let(:extension) { ' slug' }
- let(:expected_page_path) { 'page%20slug' }
- it_behaves_like 'a correct link rewrite'
+ it 'rewrites non-file links (with spaces) to be at the scope of the wiki root' do
+ markdown = "[Link to Page](page slug)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page%20slug\"")
end
- context "file links" do
- let(:extension) { '.md' }
- let(:expected_page_path) { 'nested/twice/page.md' }
- it_behaves_like 'a correct link rewrite'
+ it "rewrites file links to be at the scope of the current directory" do
+ markdown = "[Link to Page](page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
end
- context 'links with anchor' do
- let(:extension) { '#title' }
- let(:expected_page_path) { 'page#title' }
- it_behaves_like 'a correct link rewrite'
+ it 'rewrites links with anchor' do
+ markdown = '[Link to Header](start-page#title)'
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/start-page#title\"")
end
- context 'links (with spaces) with anchor' do
- let(:extension) { ' two#title' }
- let(:expected_page_path) { 'page%20two#title' }
- it_behaves_like 'a correct link rewrite'
+ it 'rewrites links (with spaces) with anchor' do
+ markdown = '[Link to Header](start page#title)'
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/start%20page#title\"")
end
end
describe "when creating root links" do
- let(:nesting) { '/' }
+ it 'rewrites non-file links to be at the scope of the wiki root' do
+ markdown = "[Link to Page](/page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
- context 'non-file links' do
- let(:extension) { '' }
- let(:expected_page_path) { 'page' }
- it_behaves_like 'a correct link rewrite'
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page\"")
end
- context 'file links' do
- let(:extension) { '.md' }
- let(:expected_page_path) { 'page.md' }
- it_behaves_like 'a correct link rewrite'
+ it 'rewrites file links to be at the scope of the wiki root' do
+ markdown = "[Link to Page](/page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page.md\"")
end
end
end
describe "linking to pages outside the wiki (absolute)" do
- let(:markdown) { "[Link to Page](http://example.com/page)" }
- let(:page_href) { 'http://example.com/page' }
- it_behaves_like 'a correct link rewrite'
+ it "doesn't rewrite links" do
+ markdown = "[Link to Page](http://example.com/page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include('href="http://example.com/page"')
+ end
end
end
end
- include_examples 'link examples', :root do
- let(:relative_url_root) { '/' }
- end
-
- include_examples 'link examples', :relative do
- let(:relative_url_root) { '/nested/relative/gitlab' }
- end
-
describe "checking slug validity when assembling links" do
context "with a valid slug" do
let(:valid_slug) { "http://example.com" }
@@ -273,54 +261,37 @@ describe Banzai::Pipeline::WikiPipeline do
end
describe 'videos and audio' do
- def src(file_name)
- "#{prefix}/nested/twice/#{file_name}"
- end
-
- shared_examples 'correct video rewrite' do
- let(:markdown) { "![video_file](#{file_name})" }
- let(:video_fragment) { "<video src=\"#{prefix}/#{expected_file_path}\"" }
- let(:options) do
- {
- project: project,
- project_wiki: project_wiki,
- page_slug: page.slug
- }
- end
+ let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") }
+ let_it_be(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) }
+ let_it_be(:project_wiki) { ProjectWiki.new(project, double(:user)) }
+ let_it_be(:page) { build(:wiki_page, wiki: project_wiki, page: OpenStruct.new(url_path: 'nested/twice/start-page')) }
- it 'generates video html structure' do
- output = described_class.to_html(markdown, options)
+ it 'generates video html structure' do
+ markdown = "![video_file](video_file_name.mp4)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
- expect(output).to include(video_fragment)
- end
+ expect(output).to include('<video src="/wiki_link_ns/wiki_link_project/wikis/nested/twice/video_file_name.mp4"')
end
- context 'underscores' do
- let(:file_name) { 'video_file_name.mp4' }
- let(:expected_file_path) { 'nested/twice/video_file_name.mp4' }
- it_behaves_like 'correct video rewrite'
- end
+ it 'rewrites and replaces video links names with white spaces to %20' do
+ markdown = "![video file](video file name.mp4)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
- context 'spaces' do
- let(:file_name) { 'video file name.mp4' }
- let(:expected_file_path) { 'nested/twice/video%20file%20name.mp4' }
- it_behaves_like 'correct video rewrite'
+ expect(output).to include('<video src="/wiki_link_ns/wiki_link_project/wikis/nested/twice/video%20file%20name.mp4"')
end
it 'generates audio html structure' do
markdown = "![audio_file](audio_file_name.wav)"
- safe_name = "audio_file_name.wav"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
- expect(output).to include(%Q'<audio src="#{src(safe_name)}"')
+ expect(output).to include('<audio src="/wiki_link_ns/wiki_link_project/wikis/nested/twice/audio_file_name.wav"')
end
it 'rewrites and replaces audio links names with white spaces to %20' do
markdown = "![audio file](audio file name.wav)"
- safe_name = "audio%20file%20name.wav"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
- expect(output).to include(%Q'<audio src="#{src(safe_name)}"')
+ expect(output).to include('<audio src="/wiki_link_ns/wiki_link_project/wikis/nested/twice/audio%20file%20name.wav"')
end
end
end
diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb
index 3ceaf159b3f..0bb9d6c331f 100644
--- a/spec/lib/gitlab/tracking_spec.rb
+++ b/spec/lib/gitlab/tracking_spec.rb
@@ -9,6 +9,7 @@ describe Gitlab::Tracking do
stub_application_setting(snowplow_collector_hostname: 'gitfoo.com')
stub_application_setting(snowplow_cookie_domain: '.gitfoo.com')
stub_application_setting(snowplow_site_id: '_abc123_')
+ stub_application_setting(snowplow_iglu_registry_url: 'https://example.org')
end
describe '.snowplow_options' do
@@ -19,7 +20,8 @@ describe Gitlab::Tracking do
cookieDomain: '.gitfoo.com',
appId: '_abc123_',
formTracking: true,
- linkClickTracking: true
+ linkClickTracking: true,
+ igluRegistryUrl: 'https://example.org'
}
expect(subject.snowplow_options(nil)).to match(expected_fields)
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index 4ed2c232f97..08d3c638f9e 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -150,7 +150,7 @@ describe Gitlab::UrlBuilder do
wiki_page = build(:wiki_page)
url = described_class.build(wiki_page)
- expect(url).to eq "#{Gitlab.config.gitlab.url}#{wiki_page.wiki.wiki_page_path}/#{wiki_page.slug}"
+ expect(url).to eq "#{Gitlab.config.gitlab.url}#{wiki_page.wiki.wiki_base_path}/#{wiki_page.slug}"
end
end
end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 8ecab12ca28..4b6c878b20d 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -19,7 +19,11 @@ describe Gitlab::UsageData do
create(:service, project: projects[2], type: 'SlackService', active: true)
create(:project_error_tracking_setting, project: projects[0])
create(:project_error_tracking_setting, project: projects[1], enabled: false)
-
+ create_list(:issue, 4, project: projects[0])
+ create(:zoom_meeting, project: projects[0], issue: projects[0].issues[0], issue_status: :added)
+ create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[1], issue_status: :removed)
+ create(:zoom_meeting, project: projects[0], issue: projects[0].issues[2], issue_status: :added)
+ create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[2], issue_status: :removed)
gcp_cluster = create(:cluster, :provided_by_gcp)
create(:cluster, :provided_by_user)
create(:cluster, :provided_by_user, :disabled)
@@ -125,6 +129,8 @@ describe Gitlab::UsageData do
in_review_folder
groups
issues
+ issues_with_associated_zoom_link
+ issues_using_zoom_quick_actions
keys
label_lists
labels
@@ -176,6 +182,8 @@ describe Gitlab::UsageData do
expect(count_data[:projects_slack_slash_active]).to eq(1)
expect(count_data[:projects_with_repositories_enabled]).to eq(3)
expect(count_data[:projects_with_error_tracking_enabled]).to eq(1)
+ expect(count_data[:issues_with_associated_zoom_link]).to eq(2)
+ expect(count_data[:issues_using_zoom_quick_actions]).to eq(3)
expect(count_data[:clusters_enabled]).to eq(7)
expect(count_data[:project_clusters_enabled]).to eq(6)
diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb
index a68434c8c66..890918d4a7c 100644
--- a/spec/lib/gitlab/utils_spec.rb
+++ b/spec/lib/gitlab/utils_spec.rb
@@ -252,41 +252,4 @@ describe Gitlab::Utils do
expect(described_class.string_to_ip_object('1:0:0:0:0:0:0:0/124')).to eq(IPAddr.new('1:0:0:0:0:0:0:0/124'))
end
end
-
- describe '.allow_hash_values' do
- it 'removes keys that do not pass the inclusion filters' do
- symbols = %i[x y z]
- ints = (0..100)
- strings = %w[foo bar baz].to_set
-
- hash = {
- a: :x,
- b: 100,
- c: 'foo',
- d: :irrelevant,
- aa: :w,
- bb: 200,
- cc: 'food',
- dd: :totally_irrelevant
- }
- allowed = {
- a: symbols,
- b: ints,
- c: strings,
- aa: symbols,
- bb: ints,
- cc: strings
- }
-
- described_class.allow_hash_values(hash, allowed)
-
- expect(hash).to eq({
- a: :x,
- b: 100,
- c: 'foo',
- d: :irrelevant,
- dd: :totally_irrelevant
- })
- end
- end
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index d16e83bb5df..b6fc152e478 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -72,10 +72,14 @@ describe ApplicationSetting do
it { is_expected.not_to allow_value(nil).for(:snowplow_collector_hostname) }
it { is_expected.to allow_value("snowplow.gitlab.com").for(:snowplow_collector_hostname) }
it { is_expected.not_to allow_value('/example').for(:snowplow_collector_hostname) }
+ it { is_expected.to allow_value('https://example.org').for(:snowplow_iglu_registry_url) }
+ it { is_expected.not_to allow_value('not-a-url').for(:snowplow_iglu_registry_url) }
+ it { is_expected.to allow_value(nil).for(:snowplow_iglu_registry_url) }
end
context 'when snowplow is not enabled' do
it { is_expected.to allow_value(nil).for(:snowplow_collector_hostname) }
+ it { is_expected.to allow_value(nil).for(:snowplow_iglu_registry_url) }
end
context 'when pendo is enabled' do
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index c1f6302ee50..4566045bffd 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -515,6 +515,48 @@ describe Environment, :use_clean_rails_memory_store_caching do
end
end
+ describe '#last_visible_deployment' do
+ subject { environment.last_visible_deployment }
+
+ before do
+ allow_any_instance_of(Deployment).to receive(:create_ref)
+ end
+
+ context 'when there is an old deployment record' do
+ let!(:previous_deployment) { create(:deployment, :success, environment: environment) }
+
+ context 'when there is a deployment record with created status' do
+ let!(:deployment) { create(:deployment, environment: environment) }
+
+ it { is_expected.to eq(previous_deployment) }
+ end
+
+ context 'when there is a deployment record with running status' do
+ let!(:deployment) { create(:deployment, :running, environment: environment) }
+
+ it { is_expected.to eq(deployment) }
+ end
+
+ context 'when there is a deployment record with success status' do
+ let!(:deployment) { create(:deployment, :success, environment: environment) }
+
+ it { is_expected.to eq(deployment) }
+ end
+
+ context 'when there is a deployment record with failed status' do
+ let!(:deployment) { create(:deployment, :failed, environment: environment) }
+
+ it { is_expected.to eq(deployment) }
+ end
+
+ context 'when there is a deployment record with canceled status' do
+ let!(:deployment) { create(:deployment, :canceled, environment: environment) }
+
+ it { is_expected.to eq(deployment) }
+ end
+ end
+ end
+
describe '#has_terminals?' do
subject { environment.has_terminals? }
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index f5c827e5a29..31d1d1fd7d1 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -28,9 +28,7 @@ describe ProjectWiki do
describe '#web_url' do
it 'returns the full web URL to the wiki' do
- home_url = Gitlab::Routing.url_helpers.project_wiki_url(project, :home)
-
- expect(subject.web_url).to eq(home_url)
+ expect(subject.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.full_path}/wikis/home")
end
end
@@ -73,23 +71,9 @@ describe ProjectWiki do
describe "#wiki_base_path" do
it "returns the wiki base path" do
- wiki_path = Gitlab::Routing.url_helpers.project_wikis_path(project)
-
- expect(subject.wiki_base_path).to eq(wiki_path)
- end
- end
+ wiki_base_path = "#{Gitlab.config.gitlab.relative_url_root}/#{project.full_path}/wikis"
- describe "#wiki_page_path" do
- let(:page) { create(:wiki_page, wiki: project_wiki) }
-
- describe 'suffixed with /:page_slug' do
- subject { "#{project_wiki.wiki_page_path}/#{page.slug}" }
-
- it "equals the project_wiki_path" do
- path = Gitlab::Routing.url_helpers.project_wiki_path(project, page)
-
- expect(subject).to eq(path)
- end
+ expect(subject.wiki_base_path).to eq(wiki_base_path)
end
end
diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb
index aff21888605..5fbcccf897e 100644
--- a/spec/models/wiki_directory_spec.rb
+++ b/spec/models/wiki_directory_spec.rb
@@ -1,94 +1,14 @@
# frozen_string_literal: true
require 'spec_helper'
-require 'set'
RSpec.describe WikiDirectory do
- include GitHelpers
-
- let(:project) { create(:project, :wiki_repo) }
- let(:user) { project.owner }
- let(:wiki) { ProjectWiki.new(project, user) }
-
describe 'validations' do
subject { build(:wiki_directory) }
it { is_expected.to validate_presence_of(:slug) }
end
- describe '.group_by_directory' do
- context 'when there are no pages' do
- it 'returns an empty array' do
- expect(described_class.group_by_directory(nil)).to eq([])
- expect(described_class.group_by_directory([])).to eq([])
- end
- end
-
- context 'when there are pages' do
- before do
- create_page('dir_1/dir_1_1/page_3', 'content')
- create_page('page_1', 'content')
- create_page('dir_1/page_2', 'content')
- create_page('dir_2', 'page with dir name')
- create_page('dir_2/page_5', 'content')
- create_page('page_6', 'content')
- create_page('dir_2/page_4', 'content')
- end
-
- let(:page_1) { wiki.find_page('page_1') }
- let(:page_6) { wiki.find_page('page_6') }
- let(:page_dir_2) { wiki.find_page('dir_2') }
-
- let(:dir_1) do
- described_class.new('dir_1', [wiki.find_page('dir_1/page_2')])
- end
- let(:dir_1_1) do
- described_class.new('dir_1/dir_1_1', [wiki.find_page('dir_1/dir_1_1/page_3')])
- end
- let(:dir_2) do
- pages = [wiki.find_page('dir_2/page_5'),
- wiki.find_page('dir_2/page_4')]
- described_class.new('dir_2', pages)
- end
-
- context "#list_pages" do
- shared_examples "a correct grouping" do
- let(:grouped_slugs) { grouped_entries.map(&method(:slugs)) }
- let(:expected_slugs) { expected_grouped_entries.map(&method(:slugs)).map(&method(:match_array)) }
-
- it 'returns an array with pages and directories' do
- expect(grouped_slugs).to match_array(expected_slugs)
- end
- end
-
- context 'sort by title' do
- let(:grouped_entries) { described_class.group_by_directory(wiki.list_pages) }
-
- let(:expected_grouped_entries) { [dir_1_1, dir_1, page_dir_2, dir_2, page_1, page_6] }
-
- it_behaves_like "a correct grouping"
- end
-
- context 'sort by created_at' do
- let(:grouped_entries) { described_class.group_by_directory(wiki.list_pages(sort: 'created_at')) }
- let(:expected_grouped_entries) { [dir_1_1, page_1, dir_1, page_dir_2, dir_2, page_6] }
-
- it_behaves_like "a correct grouping"
- end
-
- it 'returns an array with retained order with directories at the top' do
- expected_order = ['dir_1/dir_1_1/page_3', 'dir_1/page_2', 'dir_2', 'dir_2/page_4', 'dir_2/page_5', 'page_1', 'page_6']
-
- grouped_entries = described_class.group_by_directory(wiki.list_pages)
-
- actual_order = grouped_entries.flat_map(&method(:slugs))
-
- expect(actual_order).to eq(expected_order)
- end
- end
- end
- end
-
describe '#initialize' do
context 'when there are pages' do
let(:pages) { [build(:wiki_page)] }
@@ -120,112 +40,7 @@ RSpec.describe WikiDirectory do
it 'returns the relative path to the partial to be used' do
directory = build(:wiki_directory)
- expect(directory.to_partial_path).to eq('projects/wiki_directories/wiki_directory')
- end
- end
-
- describe 'attributes' do
- def page_path(index)
- "dir-path/page-#{index}"
- end
-
- let(:page_paths) { (1..3).map { |n| page_path(n) } }
-
- let(:pages) do
- page_paths.map { |p| wiki.find_page(p) }
+ expect(directory.to_partial_path).to eq('projects/wikis/wiki_directory')
end
-
- subject { described_class.new('dir-path', pages) }
-
- context 'there are no pages' do
- let(:pages) { [] }
-
- it { is_expected.to have_attributes(page_count: 0, last_version: be_nil) }
- end
-
- context 'there is one page' do
- before do
- create_page("dir-path/singleton", "Just this page")
- end
-
- let(:the_page) { wiki.find_page("dir-path/singleton") }
- let(:pages) { [the_page] }
-
- it { is_expected.to have_attributes(page_count: 1, last_version: the_page.last_version) }
- end
-
- context 'there are a few pages, each with a single version' do
- before do
- page_paths.each_with_index do |path, n|
- Timecop.freeze(Time.local(1990) + n.minutes) do
- create_page(path, "this is page #{n}")
- end
- end
- end
-
- let(:expected_last_version) { pages.last.last_version }
-
- it { is_expected.to have_attributes(page_count: 3, last_version: expected_last_version) }
- end
-
- context 'there are a few pages, each with a few versions' do
- before do
- page_paths.each_with_index do |path, n|
- t = Time.local(1990) + n.minutes
- Timecop.freeze(t) do
- create_page(path, "This is page #{n}")
- (2..3).each do |v|
- Timecop.freeze(t + v.seconds) do
- update_page(path, "Now at version #{v}")
- end
- end
- end
- end
- end
-
- it { is_expected.to have_attributes(page_count: 3, last_version: pages.last.last_version) }
- end
- end
-
- private
-
- def create_page(name, content)
- wiki.wiki.write_page(name, :markdown, content, commit_details)
- set_time(name)
- end
-
- def update_page(name, content)
- wiki.wiki.update_page(name, name, :markdown, content, update_commit_details)
- set_time(name)
- end
-
- def set_time(name)
- return unless Timecop.frozen?
-
- new_date = Time.now
- page = wiki.find_page(name).page
- commit = page.version.commit
- repo = commit.instance_variable_get(:@repository)
-
- rug_commit = rugged_repo_at_path(repo.relative_path).lookup(commit.id)
- rug_commit.amend(
- message: rug_commit.message,
- tree: rug_commit.tree,
- author: rug_commit.author.merge(time: new_date),
- committer: rug_commit.committer.merge(time: new_date),
- update_ref: 'HEAD'
- )
- end
-
- def commit_details
- Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.email, "test commit")
- end
-
- def update_commit_details
- Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.email, "test update")
- end
-
- def slugs(thing)
- Array.wrap(thing.respond_to?(:pages) ? thing.pages.map(&:slug) : thing.slug)
end
end
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index 38415613b9e..9014276dcf8 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -9,6 +9,87 @@ describe WikiPage do
subject { described_class.new(wiki) }
+ describe '.group_by_directory' do
+ context 'when there are no pages' do
+ it 'returns an empty array' do
+ expect(described_class.group_by_directory(nil)).to eq([])
+ expect(described_class.group_by_directory([])).to eq([])
+ end
+ end
+
+ context 'when there are pages' do
+ before do
+ create_page('dir_1/dir_1_1/page_3', 'content')
+ create_page('page_1', 'content')
+ create_page('dir_1/page_2', 'content')
+ create_page('dir_2', 'page with dir name')
+ create_page('dir_2/page_5', 'content')
+ create_page('page_6', 'content')
+ create_page('dir_2/page_4', 'content')
+ end
+
+ let(:page_1) { wiki.find_page('page_1') }
+ let(:page_6) { wiki.find_page('page_6') }
+ let(:page_dir_2) { wiki.find_page('dir_2') }
+
+ let(:dir_1) do
+ WikiDirectory.new('dir_1', [wiki.find_page('dir_1/page_2')])
+ end
+ let(:dir_1_1) do
+ WikiDirectory.new('dir_1/dir_1_1', [wiki.find_page('dir_1/dir_1_1/page_3')])
+ end
+ let(:dir_2) do
+ pages = [wiki.find_page('dir_2/page_5'),
+ wiki.find_page('dir_2/page_4')]
+ WikiDirectory.new('dir_2', pages)
+ end
+
+ context "#list_pages" do
+ context 'sort by title' do
+ let(:grouped_entries) { described_class.group_by_directory(wiki.list_pages) }
+ let(:expected_grouped_entries) { [dir_1_1, dir_1, page_dir_2, dir_2, page_1, page_6] }
+
+ it 'returns an array with pages and directories' do
+ grouped_entries.each_with_index do |page_or_dir, i|
+ expected_page_or_dir = expected_grouped_entries[i]
+ expected_slugs = get_slugs(expected_page_or_dir)
+ slugs = get_slugs(page_or_dir)
+
+ expect(slugs).to match_array(expected_slugs)
+ end
+ end
+ end
+
+ context 'sort by created_at' do
+ let(:grouped_entries) { described_class.group_by_directory(wiki.list_pages(sort: 'created_at')) }
+ let(:expected_grouped_entries) { [dir_1_1, page_1, dir_1, page_dir_2, dir_2, page_6] }
+
+ it 'returns an array with pages and directories' do
+ grouped_entries.each_with_index do |page_or_dir, i|
+ expected_page_or_dir = expected_grouped_entries[i]
+ expected_slugs = get_slugs(expected_page_or_dir)
+ slugs = get_slugs(page_or_dir)
+
+ expect(slugs).to match_array(expected_slugs)
+ end
+ end
+ end
+
+ it 'returns an array with retained order with directories at the top' do
+ expected_order = ['dir_1/dir_1_1/page_3', 'dir_1/page_2', 'dir_2', 'dir_2/page_4', 'dir_2/page_5', 'page_1', 'page_6']
+
+ grouped_entries = described_class.group_by_directory(wiki.list_pages)
+
+ actual_order =
+ grouped_entries.flat_map do |page_or_dir|
+ get_slugs(page_or_dir)
+ end
+ expect(actual_order).to eq(expected_order)
+ end
+ end
+ end
+ end
+
describe '.unhyphenize' do
it 'removes hyphens from a name' do
name = 'a-name--with-hyphens'
@@ -441,7 +522,7 @@ describe WikiPage do
it 'returns the relative path to the partial to be used' do
page = build(:wiki_page)
- expect(page.to_partial_path).to eq('projects/wiki_pages/wiki_page')
+ expect(page.to_partial_path).to eq('projects/wikis/wiki_page')
end
end
@@ -521,4 +602,12 @@ describe WikiPage do
page = wiki.wiki.page(title: title, dir: dir)
wiki.delete_page(page, "test commit")
end
+
+ def get_slugs(page_or_dir)
+ if page_or_dir.is_a? WikiPage
+ [page_or_dir.slug]
+ else
+ page_or_dir.pages.present? ? page_or_dir.pages.map(&:slug) : []
+ end
+ end
end
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 0f1aa9bb2bb..760eafe33e4 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -178,7 +178,8 @@ describe API::Settings, 'Settings' do
snowplow_collector_hostname: "snowplow.example.com",
snowplow_cookie_domain: ".example.com",
snowplow_enabled: true,
- snowplow_site_id: "site_id"
+ snowplow_site_id: "site_id",
+ snowplow_iglu_registry_url: 'https://example.com'
}
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 741a981a3b1..28778bf26d4 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -5,12 +5,9 @@ require 'spec_helper'
describe 'project routing' do
before do
allow(Project).to receive(:find_by_full_path).and_return(false)
- allow(Project).to receive(:find_by_full_path).with('gitlab/gitlabhq', any_args).and_return(project)
+ allow(Project).to receive(:find_by_full_path).with('gitlab/gitlabhq', any_args).and_return(true)
end
- set(:namespace) { create(:namespace, name: 'gitlab') }
- set(:project) { create(:project, namespace: namespace, name: 'gitlabhq') }
-
# Shared examples for a resource inside a Project
#
# By default it tests all the default REST actions: index, create, new, edit,
@@ -150,39 +147,24 @@ describe 'project routing' do
it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/autocomplete_sources/labels", "/gitlab/gitlabhq/-/autocomplete_sources/labels"
end
- # GET /:project_id/wikis/pages(.:format) projects/wikis#pages
- # GET /:project_id/-/wiki_pages/:id/history(.:format) projects/wiki_pages#history
- # POST /:project_id/-/wiki_pages(.:format) projects/wiki_pages#create
- # GET /:project_id/-/wiki_pages/:id/edit(.:format) projects/wiki_pages#edit
- # GET /:project_id/-/wiki_pages/:id(.:format) projects/wiki_pages#show
- # DELETE /:project_id/-/wiki_pages/:id(.:format) projects/wiki_pages#destroy
+ # pages_project_wikis GET /:project_id/wikis/pages(.:format) projects/wikis#pages
+ # history_project_wiki GET /:project_id/wikis/:id/history(.:format) projects/wikis#history
+ # project_wikis POST /:project_id/wikis(.:format) projects/wikis#create
+ # edit_project_wiki GET /:project_id/wikis/:id/edit(.:format) projects/wikis#edit
+ # project_wiki GET /:project_id/wikis/:id(.:format) projects/wikis#show
+ # DELETE /:project_id/wikis/:id(.:format) projects/wikis#destroy
describe Projects::WikisController, 'routing' do
- let(:wiki) { ProjectWiki.new(project, project.owner) }
- let(:wiki_page) { create(:wiki_page, wiki: wiki) }
-
- it '#pages' do
- expect(get('/gitlab/gitlabhq/wikis/pages'))
- .to route_to('projects/wikis#pages',
- namespace_id: 'gitlab',
- project_id: 'gitlabhq')
+ it 'to #pages' do
+ expect(get('/gitlab/gitlabhq/wikis/pages')).to route_to('projects/wikis#pages', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
- describe '#history' do
- let(:history_path) { project_wiki_history_path(project, wiki_page) }
-
- it 'routes to history' do
- expect(get(history_path))
- .to route_to('projects/wiki_pages#history',
- namespace_id: namespace.path,
- project_id: project.name,
- id: wiki_page.slug)
- end
+ it 'to #history' do
+ expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it_behaves_like 'RESTful project resources' do
let(:actions) { [:create, :edit, :show, :destroy] }
- let(:controller) { 'wiki_pages' }
- let(:controller_path) { '-/wiki_pages' }
+ let(:controller) { 'wikis' }
end
end
diff --git a/spec/routing/wiki_routing_spec.rb b/spec/routing/wiki_routing_spec.rb
deleted file mode 100644
index 94349dbaa74..00000000000
--- a/spec/routing/wiki_routing_spec.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-# We build URIs to wiki pages manually in various places (most notably
-# in markdown generation). To ensure these do not get out of sync, these
-# tests verify that our path generation assumptions are sound.
-describe 'Wiki path generation assumptions' do
- set(:project) { create(:project, :public, :repository) }
-
- let(:project_wiki) { ProjectWiki.new(project, project.owner) }
- let(:some_page_name) { 'some-wiki-page' }
- let(:wiki_page) do
- create(:wiki_page, wiki: project_wiki, attrs: { title: some_page_name })
- end
-
- describe 'WikiProject#wiki_page_path', 'routing' do
- it 'is consistent with routing to wiki#show' do
- uri = URI.parse(project_wiki.wiki_page_path)
- path = ::File.join(uri.path, some_page_name)
-
- expect(get('/' + path)).to route_to('projects/wiki_pages#show',
- id: some_page_name,
- namespace_id: project.namespace.to_param,
- project_id: project.to_param)
- end
- end
-
- describe 'project_wiki_path', 'routing' do
- describe 'GET' do
- it 'routes to the :show action' do
- path = project_wiki_path(project, wiki_page)
-
- expect(get('/' + path)).to route_to('projects/wiki_pages#show',
- id: wiki_page.slug,
- namespace_id: project.namespace.to_param,
- project_id: project.to_param)
- end
- end
- end
-
- describe 'project_wiki_pages_new_path', 'routing' do
- describe 'GET' do
- it 'routes to the :new action' do
- path = project_wiki_pages_new_path(project)
-
- expect(get('/' + path)).to route_to('projects/wiki_pages#new',
- namespace_id: project.namespace.to_param,
- project_id: project.to_param)
- end
- end
- end
-
- # Early versions of the wiki paths routed all wiki pages at
- # /wikis/:id - this test exists to guarantee that we support
- # old URIs that may be out there, saved in bookmarks, on other wikis, etc.
- describe 'legacy route support', type: 'request' do
- let(:path) { ::File.join(project_wikis_path(project), some_page_name) }
-
- before do
- get(path)
- end
-
- it 'routes to new wiki paths' do
- dest = project_wiki_path(project, wiki_page)
-
- expect(response).to redirect_to(dest)
- end
-
- context 'the page is nested in a directory' do
- let(:some_page_name) { 'some-dir/some-deep-dir/some-page' }
- let(:path) { ::File.join(project_wikis_path(project), some_page_name) }
-
- it 'still routes correctly' do
- dest = project_wiki_path(project, wiki_page)
-
- expect(response).to redirect_to(dest)
- end
- end
-
- context 'the user requested the old history path' do
- let(:some_page_name) { 'some-dir/some-deep-dir/some-page' }
- let(:path) { ::File.join(project_wikis_path(project), some_page_name, 'history') }
-
- it 'redirects to the new history path' do
- dest = project_wiki_history_path(project, wiki_page)
-
- expect(response).to redirect_to(dest)
- end
- end
-
- context 'the user requested the old edit path' do
- let(:some_page_name) { 'some-dir/some-deep-dir/some-page' }
- let(:path) { ::File.join(project_wikis_path(project), some_page_name, 'edit') }
-
- it 'redirects to the new history path' do
- dest = project_wiki_edit_path(project, wiki_page)
-
- expect(response).to redirect_to(dest)
- end
- end
- end
-end
diff --git a/spec/support/controllers/authorization_helpers.rb b/spec/support/controllers/authorization_helpers.rb
deleted file mode 100644
index e1786e0ca8a..00000000000
--- a/spec/support/controllers/authorization_helpers.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# frozen_string_literal: true
-
-def forbid_controller_ability!(ability)
- allow(controller).to receive(:can?).and_call_original
- allow(controller).to receive(:can?).with(anything, ability, any_args).and_return(false)
-end
diff --git a/spec/support/helpers/capybara_helpers.rb b/spec/support/helpers/capybara_helpers.rb
index 13ec179b734..a7baa7042c9 100644
--- a/spec/support/helpers/capybara_helpers.rb
+++ b/spec/support/helpers/capybara_helpers.rb
@@ -46,14 +46,4 @@ module CapybaraHelpers
def javascript_test?
Capybara.current_driver == Capybara.javascript_driver
end
-
- def scroll_to(element)
- raise 'JS not available' unless javascript_test?
-
- script = <<-JS
- arguments[0].scrollIntoView(true);
- JS
-
- page.driver.browser.execute_script(script, element.native)
- end
end
diff --git a/spec/support/helpers/dropzone_helper.rb b/spec/support/helpers/dropzone_helper.rb
index 3f37673dadd..a0f261b312e 100644
--- a/spec/support/helpers/dropzone_helper.rb
+++ b/spec/support/helpers/dropzone_helper.rb
@@ -14,8 +14,6 @@ module DropzoneHelper
# If it's 'false', then the helper will NOT wait for backend response
# It lets to test behaviors while AJAX is processing.
def dropzone_file(files, max_file_size = 0, wait_for_queuecomplete = true)
- # Assert that there is a dropzone to use (waiting until it is ready)
- expect(page).to have_css('.div-dropzone')
# Generate a fake file input that Capybara can attach to
page.execute_script <<-JS.strip_heredoc
$('#fakeFileInput').remove();
diff --git a/spec/support/helpers/git_helpers.rb b/spec/support/helpers/git_helpers.rb
index 05e31a1154a..99c5871ba54 100644
--- a/spec/support/helpers/git_helpers.rb
+++ b/spec/support/helpers/git_helpers.rb
@@ -2,11 +2,8 @@
module GitHelpers
def rugged_repo(repository)
- rugged_repo_at_path(repository.disk_path + '.git')
- end
+ path = File.join(TestEnv.repos_path, repository.disk_path + '.git')
- def rugged_repo_at_path(relative_path)
- path = File.join(TestEnv.repos_path, relative_path)
Rugged::Repository.new(path)
end
end
diff --git a/spec/support/helpers/wiki_helpers.rb b/spec/support/helpers/wiki_helpers.rb
index 0cf70fd4ef7..06cea728b42 100644
--- a/spec/support/helpers/wiki_helpers.rb
+++ b/spec/support/helpers/wiki_helpers.rb
@@ -12,10 +12,4 @@ module WikiHelpers
::Wikis::CreateAttachmentService.new(project, user, opts)
.execute[:result][:file_path]
end
-
- # Generate the form field name for a given attribute of an object.
- # This is rather general, but is currently only used in the wiki featur tests.
- def form_field_name(obj, attr_name)
- "#{ActiveModel::Naming.param_key(obj)}[#{attr_name}]"
- end
end
diff --git a/spec/support/matchers/issuable_matchers.rb b/spec/support/matchers/issuable_matchers.rb
index ab15a80bf60..743f0b8c932 100644
--- a/spec/support/matchers/issuable_matchers.rb
+++ b/spec/support/matchers/issuable_matchers.rb
@@ -2,8 +2,7 @@
RSpec::Matchers.define :have_header_with_correct_id_and_link do |level, text, id, parent = ".md"|
match do |actual|
- # anchors may be invisible
- node = find("#{parent} h#{level} a#user-content-#{id}", visible: false)
+ node = find("#{parent} h#{level} a#user-content-#{id}")
expect(node[:href]).to end_with("##{id}")
diff --git a/spec/support/shared_examples/requests/api/discussions.rb b/spec/support/shared_examples/requests/api/discussions.rb
index a36bc2dc9b5..2a5a48f3054 100644
--- a/spec/support/shared_examples/requests/api/discussions.rb
+++ b/spec/support/shared_examples/requests/api/discussions.rb
@@ -117,6 +117,29 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name, can_r
expect(response).to have_gitlab_http_status(401)
end
+ it 'tracks a Notes::CreateService event' do
+ expect(Gitlab::Tracking).to receive(:event) do |category, action, data|
+ expect(category).to eq('Notes::CreateService')
+ expect(action).to eq('execute')
+ expect(data[:label]).to eq('note')
+ expect(data[:value]).to be_an(Integer)
+ end
+
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), params: { body: 'hi!' }
+ end
+
+ context 'with notes_create_service_tracking feature flag disabled' do
+ before do
+ stub_feature_flags(notes_create_service_tracking: false)
+ end
+
+ it 'does not track any events' do
+ expect(Gitlab::Tracking).not_to receive(:event)
+
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), params: { body: 'hi!' }
+ end
+ end
+
context 'when an admin or owner makes the request' do
it 'accepts the creation date to be set' do
creation_time = 2.weeks.ago
diff --git a/spec/support/shared_examples/wiki_file_attachments_examples.rb b/spec/support/shared_examples/wiki_file_attachments_examples.rb
index a43b7c0300f..22fbfb48928 100644
--- a/spec/support/shared_examples/wiki_file_attachments_examples.rb
+++ b/spec/support/shared_examples/wiki_file_attachments_examples.rb
@@ -42,7 +42,7 @@ shared_examples 'wiki file attachments' do
end
end
- context 'uploading is complete' do
+ context 'uploading is complete', :quarantine do
it 'shows "Attach a file" button on uploading complete' do
attach_with_dropzone
wait_for_requests
@@ -52,11 +52,11 @@ shared_examples 'wiki file attachments' do
end
it 'the markdown link is added to the page' do
- fill_in(:wiki_page_content, with: '')
+ fill_in(:wiki_content, with: '')
attach_with_dropzone(true)
wait_for_requests
- expect(page.find('#wiki_page_content').value)
+ expect(page.find('#wiki_content').value)
.to match(%r{\!\[dk\]\(uploads/\h{32}/dk\.png\)$})
end
@@ -70,7 +70,7 @@ shared_examples 'wiki file attachments' do
img_link = page.find('a.no-attachment-icon img')['src']
expect(link).to eq img_link
- expect(URI.parse(link).path).to eq File.join(wiki.wiki_page_path, file_path)
+ expect(URI.parse(link).path).to eq File.join(wiki.wiki_base_path, file_path)
end
it 'the file has been added to the wiki repository' do