Commit fe5533a7 authored by Markus Koller's avatar Markus Koller

Add group wiki model

- Refactor existing `ProjectWiki` into `Wiki`, and add new child classes
  `ProjectWiki` and `GroupWiki`.
- Rename `project` to `container` in the wiki classes.
- Add `HasWiki` concern for use in `Project` and `Group`.
- Add `@groups` prefix in `Storage::Hashed`.
- Refactor existing specs into shared examples.
parent 61cdcb8f
...@@ -475,7 +475,6 @@ Style/MixinUsage: ...@@ -475,7 +475,6 @@ Style/MixinUsage:
Style/MultilineIfModifier: Style/MultilineIfModifier:
Exclude: Exclude:
- 'app/helpers/snippets_helper.rb' - 'app/helpers/snippets_helper.rb'
- 'app/models/project_wiki.rb'
- 'app/services/ci/process_pipeline_service.rb' - 'app/services/ci/process_pipeline_service.rb'
- 'lib/api/commit_statuses.rb' - 'lib/api/commit_statuses.rb'
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
# needs any special behavior. # needs any special behavior.
module HasRepository module HasRepository
extend ActiveSupport::Concern extend ActiveSupport::Concern
include AfterCommitQueue
include Referable include Referable
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
......
# frozen_string_literal: true
module HasWiki
extend ActiveSupport::Concern
included do
validate :check_wiki_path_conflict
end
def create_wiki
wiki.wiki
true
rescue Wiki::CouldNotCreateWikiError
errors.add(:base, _('Failed to create wiki'))
false
end
def wiki
strong_memoize(:wiki) do
Wiki.for_container(self, self.owner)
end
end
def wiki_repository_exists?
wiki.repository_exists?
end
def after_wiki_activity
true
end
private
def check_wiki_path_conflict
return if path.blank?
path_to_check = path.ends_with?('.wiki') ? path.chomp('.wiki') : "#{path}.wiki"
if Project.in_namespace(parent_id).where(path: path_to_check).exists? ||
GroupsFinder.new(nil, parent: parent_id).execute.where(path: path_to_check).exists?
errors.add(:name, _('has already been taken'))
end
end
end
# frozen_string_literal: true
module Storage
module LegacyProjectWiki
extend ActiveSupport::Concern
def disk_path
project.disk_path + '.wiki'
end
end
end
...@@ -15,6 +15,7 @@ class Group < Namespace ...@@ -15,6 +15,7 @@ class Group < Namespace
include WithUploads include WithUploads
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include GroupAPICompatibility include GroupAPICompatibility
include HasWiki
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10 ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10
......
# frozen_string_literal: true
class GroupWiki < Wiki
alias_method :group, :container
override :storage
def storage
@storage ||= Storage::Hashed.new(container, prefix: Storage::Hashed::GROUP_REPOSITORY_PATH_PREFIX)
end
override :repository_storage
def repository_storage
# TODO: Add table to track storage
# https://gitlab.com/gitlab-org/gitlab/-/issues/207865
'default'
end
override :hashed_storage?
def hashed_storage?
true
end
override :disk_path
def disk_path(*args, &block)
storage.disk_path + '.wiki'
end
end
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
class Project < ApplicationRecord class Project < ApplicationRecord
extend ::Gitlab::Utils::Override
include Gitlab::ConfigHelper include Gitlab::ConfigHelper
include Gitlab::VisibilityLevel include Gitlab::VisibilityLevel
include AccessRequestable include AccessRequestable
...@@ -18,6 +19,7 @@ class Project < ApplicationRecord ...@@ -18,6 +19,7 @@ class Project < ApplicationRecord
include SelectForProjectAuthorization include SelectForProjectAuthorization
include Presentable include Presentable
include HasRepository include HasRepository
include HasWiki
include Routable include Routable
include GroupDescendant include GroupDescendant
include Gitlab::SQL::Pattern include Gitlab::SQL::Pattern
...@@ -386,7 +388,6 @@ class Project < ApplicationRecord ...@@ -386,7 +388,6 @@ class Project < ApplicationRecord
validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? } validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? }
validate :visibility_level_allowed_by_group, if: :should_validate_visibility_level? validate :visibility_level_allowed_by_group, if: :should_validate_visibility_level?
validate :visibility_level_allowed_as_fork, if: :should_validate_visibility_level? validate :visibility_level_allowed_as_fork, if: :should_validate_visibility_level?
validate :check_wiki_path_conflict
validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) } validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) }
validates :repository_storage, validates :repository_storage,
presence: true, presence: true,
...@@ -1051,16 +1052,6 @@ class Project < ApplicationRecord ...@@ -1051,16 +1052,6 @@ class Project < ApplicationRecord
self.errors.add(:visibility_level, _("%{level_name} is not allowed since the fork source project has lower visibility.") % { level_name: level_name }) self.errors.add(:visibility_level, _("%{level_name} is not allowed since the fork source project has lower visibility.") % { level_name: level_name })
end end
def check_wiki_path_conflict
return if path.blank?
path_to_check = path.ends_with?('.wiki') ? path.chomp('.wiki') : "#{path}.wiki"
if Project.where(namespace_id: namespace_id, path: path_to_check).exists?
errors.add(:name, _('has already been taken'))
end
end
def pages_https_only def pages_https_only
return false unless Gitlab.config.pages.external_https return false unless Gitlab.config.pages.external_https
...@@ -1560,10 +1551,6 @@ class Project < ApplicationRecord ...@@ -1560,10 +1551,6 @@ class Project < ApplicationRecord
create_repository(force: true) unless repository_exists? create_repository(force: true) unless repository_exists?
end end
def wiki_repository_exists?
wiki.repository_exists?
end
# update visibility_level of forks # update visibility_level of forks
def update_forks_visibility_level def update_forks_visibility_level
return if unlink_forks_upon_visibility_decrease_enabled? return if unlink_forks_upon_visibility_decrease_enabled?
...@@ -1577,20 +1564,6 @@ class Project < ApplicationRecord ...@@ -1577,20 +1564,6 @@ class Project < ApplicationRecord
end end
end end
def create_wiki
ProjectWiki.new(self, self.owner).wiki
true
rescue ProjectWiki::CouldNotCreateWikiError
errors.add(:base, _('Failed create wiki'))
false
end
def wiki
strong_memoize(:wiki) do
ProjectWiki.new(self, self.owner)
end
end
def allowed_to_share_with_group? def allowed_to_share_with_group?
!namespace.share_with_group_lock !namespace.share_with_group_lock
end end
...@@ -2420,6 +2393,11 @@ class Project < ApplicationRecord ...@@ -2420,6 +2393,11 @@ class Project < ApplicationRecord
jira_imports.last jira_imports.last
end end
override :after_wiki_activity
def after_wiki_activity
touch(:last_activity_at, :last_repository_updated_at)
end
private private
def find_service(services, name) def find_service(services, name)
......
# frozen_string_literal: true # frozen_string_literal: true
class ProjectWiki class ProjectWiki < Wiki
include Storage::LegacyProjectWiki alias_method :project, :container
include Gitlab::Utils::StrongMemoize
MARKUPS = { # Project wikis are tied to the main project storage
'Markdown' => :markdown, delegate :storage, :repository_storage, :hashed_storage?, to: :container
'RDoc' => :rdoc,
'AsciiDoc' => :asciidoc,
'Org' => :org
}.freeze unless defined?(MARKUPS)
CouldNotCreateWikiError = Class.new(StandardError) override :disk_path
SIDEBAR = '_sidebar' def disk_path(*args, &block)
container.disk_path + '.wiki'
TITLE_ORDER = 'title'
CREATED_AT_ORDER = 'created_at'
DIRECTION_DESC = 'desc'
DIRECTION_ASC = 'asc'
attr_reader :project, :user
# Returns a string describing what went wrong after
# an operation fails.
attr_reader :error_message
def initialize(project, user = nil)
@project = project
@user = user
end
delegate :repository_storage, :hashed_storage?, to: :project
def path
@project.path + '.wiki'
end
def full_path
@project.full_path + '.wiki'
end
alias_method :id, :full_path
# @deprecated use full_path when you need it for an URL route or disk_path when you want to point to the filesystem
alias_method :path_with_namespace, :full_path
def web_url(only_path: nil)
Gitlab::UrlBuilder.build(self, only_path: only_path)
end
def url_to_repo
ssh_url_to_repo
end
def ssh_url_to_repo
Gitlab::RepositoryUrlBuilder.build(repository.full_path, protocol: :ssh)
end
def http_url_to_repo
Gitlab::RepositoryUrlBuilder.build(repository.full_path, protocol: :http)
end
def wiki_base_path
[Gitlab.config.gitlab.relative_url_root, '/', @project.full_path, '/-', '/wikis'].join('')
end
# Returns the Gitlab::Git::Wiki object.
def wiki
strong_memoize(:wiki) do
repository.create_if_not_exists
raise CouldNotCreateWikiError unless repository_exists?
Gitlab::Git::Wiki.new(repository.raw)
end
rescue => err
Gitlab::ErrorTracking.track_exception(err, project_wiki: { project_id: project.id, full_path: full_path, disk_path: disk_path })
raise CouldNotCreateWikiError
end
def repository_exists?
!!repository.exists?
end
def has_home_page?
!!find_page('home')
end
def empty?
list_pages(limit: 1).empty?
end
def exists?
!empty?
end
# Lists wiki pages of the repository.
#
# limit - max number of pages returned by the method.
# sort - criterion by which the pages are sorted.
# direction - order of the sorted pages.
# load_content - option, which specifies whether the content inside the page
# will be loaded.
#
# Returns an Array of GitLab WikiPage instances or an
# empty Array if this Wiki has no pages.
def list_pages(limit: 0, sort: nil, direction: DIRECTION_ASC, load_content: false)
wiki.list_pages(
limit: limit,
sort: sort,
direction_desc: direction == DIRECTION_DESC,
load_content: load_content
).map do |page|
WikiPage.new(self, page)
end
end
# Finds a page within the repository based on a tile
# or slug.
#
# title - The human readable or parameterized title of
# the page.
#
# Returns an initialized WikiPage instance or nil
def find_page(title, version = nil)
page_title, page_dir = page_title_and_dir(title)
if page = wiki.page(title: page_title, version: version, dir: page_dir)
WikiPage.new(self, page)
end
end
def find_sidebar(version = nil)
find_page(SIDEBAR, version)
end
def find_file(name, version = nil)
wiki.file(name, version)
end
def create_page(title, content, format = :markdown, message = nil)
commit = commit_details(:created, message, title)
wiki.write_page(title, format.to_sym, content, commit)
update_project_activity
rescue Gitlab::Git::Wiki::DuplicatePageError => e
@error_message = "Duplicate page: #{e.message}"
false
end
def update_page(page, content:, title: nil, format: :markdown, message: nil)
commit = commit_details(:updated, message, page.title)
wiki.update_page(page.path, title || page.name, format.to_sym, content, commit)
update_project_activity
end
def delete_page(page, message = nil)
return unless page
wiki.delete_page(page.path, commit_details(:deleted, message, page.title))
update_project_activity
end
def page_title_and_dir(title)
return unless title
title_array = title.split("/")
title = title_array.pop
[title, title_array.join("/")]
end
def repository
@repository ||= Repository.new(full_path, @project, shard: repository_storage, disk_path: disk_path, repo_type: Gitlab::GlRepository::WIKI)
end
def default_branch
wiki.class.default_ref
end
def ensure_repository
raise CouldNotCreateWikiError unless wiki.repository_exists?
end
def hook_attrs
{
web_url: web_url,
git_ssh_url: ssh_url_to_repo,
git_http_url: http_url_to_repo,
path_with_namespace: full_path,
default_branch: default_branch
}
end
private
def commit_details(action, message = nil, title = nil)
commit_message = message.presence || default_message(action, title)
git_user = Gitlab::Git::User.from_gitlab(user)
Gitlab::Git::Wiki::CommitDetails.new(user.id,
git_user.username,
git_user.name,
git_user.email,
commit_message)
end
def default_message(action, title)
"#{user.username} #{action} page: #{title}"
end
def update_project_activity
@project.touch(:last_activity_at, :last_repository_updated_at)
end end
end end
# TODO: Remove this once we implement ES support for group wikis.
# https://gitlab.com/gitlab-org/gitlab/-/issues/207889
ProjectWiki.prepend_if_ee('EE::ProjectWiki') ProjectWiki.prepend_if_ee('EE::ProjectWiki')
...@@ -15,6 +15,7 @@ class Snippet < ApplicationRecord ...@@ -15,6 +15,7 @@ class Snippet < ApplicationRecord
include FromUnion include FromUnion
include IgnorableColumns include IgnorableColumns
include HasRepository include HasRepository
include AfterCommitQueue
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
MAX_FILE_COUNT = 1 MAX_FILE_COUNT = 1
......
...@@ -6,6 +6,7 @@ module Storage ...@@ -6,6 +6,7 @@ module Storage
delegate :gitlab_shell, :repository_storage, to: :container delegate :gitlab_shell, :repository_storage, to: :container
REPOSITORY_PATH_PREFIX = '@hashed' REPOSITORY_PATH_PREFIX = '@hashed'
GROUP_REPOSITORY_PATH_PREFIX = '@groups'
SNIPPET_REPOSITORY_PATH_PREFIX = '@snippets' SNIPPET_REPOSITORY_PATH_PREFIX = '@snippets'
POOL_PATH_PREFIX = '@pools' POOL_PATH_PREFIX = '@pools'
......
# frozen_string_literal: true
class Wiki
extend ::Gitlab::Utils::Override
include HasRepository
include Gitlab::Utils::StrongMemoize
MARKUPS = { # rubocop:disable Style/MultilineIfModifier
'Markdown' => :markdown,
'RDoc' => :rdoc,
'AsciiDoc' => :asciidoc,
'Org' => :org
}.freeze unless defined?(MARKUPS)
CouldNotCreateWikiError = Class.new(StandardError)
HOMEPAGE = 'home'
SIDEBAR = '_sidebar'
TITLE_ORDER = 'title'
CREATED_AT_ORDER = 'created_at'
DIRECTION_DESC = 'desc'
DIRECTION_ASC = 'asc'
attr_reader :container, :user
# Returns a string describing what went wrong after
# an operation fails.
attr_reader :error_message
def self.for_container(container, user = nil)
"#{container.class.name}Wiki".constantize.new(container, user)
end
def initialize(container, user = nil)
@container = container
@user = user
end
def path
container.path + '.wiki'
end
# Returns the Gitlab::Git::Wiki object.
def wiki
strong_memoize(:wiki) do
repository.create_if_not_exists
raise CouldNotCreateWikiError unless repository_exists?
Gitlab::Git::Wiki.new(repository.raw)
end
rescue => err
Gitlab::ErrorTracking.track_exception(err, wiki: {
container_type: container.class.name,
container_id: container.id,
full_path: full_path,
disk_path: disk_path
})
raise CouldNotCreateWikiError
end
def has_home_page?
!!find_page(HOMEPAGE)
end
def empty?
list_pages(limit: 1).empty?
end
def exists?
!empty?
end
# Lists wiki pages of the repository.
#
# limit - max number of pages returned by the method.
# sort - criterion by which the pages are sorted.
# direction - order of the sorted pages.
# load_content - option, which specifies whether the content inside the page
# will be loaded.
#
# Returns an Array of GitLab WikiPage instances or an
# empty Array if this Wiki has no pages.
def list_pages(limit: 0, sort: nil, direction: DIRECTION_ASC, load_content: false)
wiki.list_pages(
limit: limit,
sort: sort,
direction_desc: direction == DIRECTION_DESC,
load_content: load_content
).map do |page|
WikiPage.new(self, page)
end
end
# Finds a page within the repository based on a tile
# or slug.
#
# title - The human readable or parameterized title of
# the page.
#
# Returns an initialized WikiPage instance or nil
def find_page(title, version = nil)
page_title, page_dir = page_title_and_dir(title)
if page = wiki.page(title: page_title, version: version, dir: page_dir)
WikiPage.new(self, page)
end
end
def find_sidebar(version = nil)
find_page(SIDEBAR, version)
end
def find_file(name, version = nil)
wiki.file(name, version)
end
def create_page(title, content, format = :markdown, message = nil)
commit = commit_details(:created, message, title)
wiki.write_page(title, format.to_sym, content, commit)
update_container_activity
rescue Gitlab::Git::Wiki::DuplicatePageError => e
@error_message = "Duplicate page: #{e.message}"
false
end
def update_page(page, content:, title: nil, format: :markdown, message: nil)
commit = commit_details(:updated, message, page.title)
wiki.update_page(page.path, title || page.name, format.to_sym, content, commit)
update_container_activity
end
def delete_page(page, message = nil)
return unless page
wiki.delete_page(page.path, commit_details(:deleted, message, page.title))
update_container_activity
end
def page_title_and_dir(title)
return unless title
title_array = title.split("/")
title = title_array.pop
[title, title_array.join("/")]
end
def ensure_repository
raise CouldNotCreateWikiError unless wiki.repository_exists?
end
def hook_attrs
{
web_url: web_url,
git_ssh_url: ssh_url_to_repo,
git_http_url: http_url_to_repo,
path_with_namespace: full_path,
default_branch: default_branch
}
end
override :repository
def repository
@repository ||= Repository.new(full_path, container, shard: repository_storage, disk_path: disk_path, repo_type: Gitlab::GlRepository::WIKI)
end
def repository_storage
raise NotImplementedError
end
def hashed_storage?
raise NotImplementedError
end
override :full_path
def full_path
container.full_path + '.wiki'
end
alias_method :id, :full_path
# @deprecated use full_path when you need it for an URL route or disk_path when you want to point to the filesystem
alias_method :path_with_namespace, :full_path
override :default_branch
def default_branch
wiki.class.default_ref
end
def wiki_base_path
Gitlab.config.gitlab.relative_url_root + web_url(only_path: true).sub(%r{/#{Wiki::HOMEPAGE}\z}, '')
end
private
def commit_details(action, message = nil, title = nil)
commit_message = message.presence || default_message(action, title)
git_user = Gitlab::Git::User.from_gitlab(user)
Gitlab::Git::Wiki::CommitDetails.new(user.id,
git_user.username,
git_user.name,
git_user.email,
commit_message)
end
def default_message(action, title)
"#{user.username} #{action} page: #{title}"
end
def update_container_activity
container.after_wiki_activity
end
end
Wiki.prepend_if_ee('EE::Wiki')
...@@ -26,7 +26,7 @@ class WikiPage ...@@ -26,7 +26,7 @@ class WikiPage
def eql?(other) def eql?(other)
return false unless other.present? && other.is_a?(self.class) return false unless other.present? && other.is_a?(self.class)
slug == other.slug && wiki.project == other.wiki.project slug == other.slug && wiki.container == other.wiki.container
end end
alias_method :==, :eql? alias_method :==, :eql?
...@@ -66,9 +66,9 @@ class WikiPage ...@@ -66,9 +66,9 @@ class WikiPage
validates :content, presence: true validates :content, presence: true
validate :validate_path_limits, if: :title_changed? validate :validate_path_limits, if: :title_changed?
# The GitLab ProjectWiki instance. # The GitLab Wiki instance.
attr_reader :wiki attr_reader :wiki
delegate :project, to: :wiki delegate :container, to: :wiki
# The raw Gitlab::Git::WikiPage instance. # The raw Gitlab::Git::WikiPage instance.
attr_reader :page attr_reader :page
...@@ -83,7 +83,7 @@ class WikiPage ...@@ -83,7 +83,7 @@ class WikiPage
# Construct a new WikiPage # Construct a new WikiPage
# #
# @param [ProjectWiki] wiki # @param [Wiki] wiki
# @param [Gitlab::Git::WikiPage] page # @param [Gitlab::Git::WikiPage] page
def initialize(wiki, page = nil) def initialize(wiki, page = nil)
@wiki = wiki @wiki = wiki
...@@ -195,7 +195,7 @@ class WikiPage ...@@ -195,7 +195,7 @@ class WikiPage
# :content - The raw markup content. # :content - The raw markup content.
# :format - Optional symbol representing the # :format - Optional symbol representing the
# content format. Can be any type # content format. Can be any type
# listed in the ProjectWiki::MARKUPS # listed in the Wiki::MARKUPS
# Hash. # Hash.
# :message - Optional commit message to set on # :message - Optional commit message to set on
# the new page. # the new page.
...@@ -215,7 +215,7 @@ class WikiPage ...@@ -215,7 +215,7 @@ class WikiPage
# attrs - Hash of attributes to be updated on the page. # attrs - Hash of attributes to be updated on the page.
# :content - The raw markup content to replace the existing. # :content - The raw markup content to replace the existing.
# :format - Optional symbol representing the content format. # :format - Optional symbol representing the content format.
# See ProjectWiki::MARKUPS Hash for available formats. # See Wiki::MARKUPS Hash for available formats.
# :message - Optional commit message to set on the new version. # :message - Optional commit message to set on the new version.
# :last_commit_sha - Optional last commit sha to validate the page unchanged. # :last_commit_sha - Optional last commit sha to validate the page unchanged.
# :title - The Title (optionally including dir) to replace existing title # :title - The Title (optionally including dir) to replace existing title
...@@ -261,6 +261,7 @@ class WikiPage ...@@ -261,6 +261,7 @@ class WikiPage
# Relative path to the partial to be used when rendering collections # Relative path to the partial to be used when rendering collections
# of this object. # of this object.
def to_partial_path def to_partial_path
# TODO: Move into shared/ with https://gitlab.com/gitlab-org/gitlab/-/issues/196054
'projects/wikis/wiki_page' 'projects/wikis/wiki_page'
end end
...@@ -303,7 +304,7 @@ class WikiPage ...@@ -303,7 +304,7 @@ class WikiPage
end end
def update_front_matter(attrs) def update_front_matter(attrs)
return unless Gitlab::WikiPages::FrontMatterParser.enabled?(project) return unless Gitlab::WikiPages::FrontMatterParser.enabled?(container)
return unless attrs.has_key?(:front_matter) return unless attrs.has_key?(:front_matter)
fm_yaml = serialize_front_matter(attrs[:front_matter]) fm_yaml = serialize_front_matter(attrs[:front_matter])
...@@ -314,7 +315,7 @@ class WikiPage ...@@ -314,7 +315,7 @@ class WikiPage
def parsed_content def parsed_content
strong_memoize(:parsed_content) do strong_memoize(:parsed_content) do
Gitlab::WikiPages::FrontMatterParser.new(raw_content, project).parse Gitlab::WikiPages::FrontMatterParser.new(raw_content, container).parse
end end
end end
......
# frozen_string_literal: true # frozen_string_literal: true
class WikiPagePolicy < BasePolicy class WikiPagePolicy < BasePolicy
delegate { @subject.wiki.project } delegate { @subject.wiki.container }
rule { can?(:read_wiki) }.enable :read_wiki_page rule { can?(:read_wiki) }.enable :read_wiki_page
end end
...@@ -3,22 +3,11 @@ ...@@ -3,22 +3,11 @@
module EE module EE
module ProjectWiki module ProjectWiki
extend ActiveSupport::Concern extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
prepended do prepended do
# TODO: Move this into EE::Wiki once we implement ES support for group wikis.
# https://gitlab.com/gitlab-org/gitlab/-/issues/207889
include Elastic::WikiRepositoriesSearch include Elastic::WikiRepositoriesSearch
end end
# No need to have a Kerberos Web url. Kerberos URL will be used only to
# clone
def kerberos_url_to_repo
[::Gitlab.config.build_gitlab_kerberos_url, '/', full_path, '.git'].join('')
end
def path_to_repo
@path_to_repo ||=
File.join(::Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path,
"#{disk_path}.git")
end
end end
end end
# frozen_string_literal: true
module EE
module Wiki
extend ActiveSupport::Concern
# No need to have a Kerberos Web url. Kerberos URL will be used only to
# clone
def kerberos_url_to_repo
[::Gitlab.config.build_gitlab_kerberos_url, '/', full_path, '.git'].join('')
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe GroupWiki do
it_behaves_like 'EE wiki model' do
let(:wiki_container) { create(:group, :wiki_repo) }
before do
wiki_container.add_owner(user)
end
it 'does not use Elasticsearch' do
expect(subject).not_to be_a(Elastic::WikiRepositoriesSearch)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe ProjectWiki do
it_behaves_like 'EE wiki model' do
let(:wiki_container) { create(:project, :wiki_repo, namespace: user.namespace) }
it 'uses Elasticsearch' do
expect(subject).to be_a(Elastic::WikiRepositoriesSearch)
end
end
end
# frozen_string_literal: true # frozen_string_literal: true
require "spec_helper" RSpec.shared_examples_for 'EE wiki model' do
let_it_be(:user) { create(:user) }
let(:wiki) { described_class.for_container(wiki_container, user) }
describe ProjectWiki do subject { wiki }
let(:user) { create(:user, :commit_email) }
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:project_wiki) { described_class.new(project, user) }
subject { project_wiki } describe '#kerberos_url_to_repo' do
describe "#kerberos_url_to_repo" do
it 'returns valid kerberos url for this repo' do it 'returns valid kerberos url for this repo' do
gitlab_kerberos_url = Gitlab.config.build_gitlab_kerberos_url gitlab_kerberos_url = Gitlab.config.build_gitlab_kerberos_url
repo_kerberos_url = "#{gitlab_kerberos_url}/#{subject.full_path}.git" repo_kerberos_url = "#{gitlab_kerberos_url}/#{subject.full_path}.git"
......
...@@ -34,8 +34,8 @@ module Gitlab ...@@ -34,8 +34,8 @@ module Gitlab
snippet_url(object, **options) snippet_url(object, **options)
when User when User
instance.user_url(object, **options) instance.user_url(object, **options)
when ProjectWiki when Wiki
instance.project_wiki_url(object.project, :home, **options) wiki_url(object, **options)
when WikiPage when WikiPage
instance.project_wiki_url(object.wiki.project, object.slug, **options) instance.project_wiki_url(object.wiki.project, object.slug, **options)
else else
...@@ -70,6 +70,19 @@ module Gitlab ...@@ -70,6 +70,19 @@ module Gitlab
instance.gitlab_snippet_url(snippet, **options) instance.gitlab_snippet_url(snippet, **options)
end end
end end
def wiki_url(object, **options)
case object.container
when Project
instance.project_wiki_url(object.container, Wiki::HOMEPAGE, **options)
when Group
# TODO: Use the new route for group wikis once we add it.
# https://gitlab.com/gitlab-org/gitlab/-/issues/211360
instance.group_canonical_url(object.container, **options) + "/-/wikis/#{Wiki::HOMEPAGE}"
else
raise NotImplementedError.new("No URL builder defined for #{object.inspect}")
end
end
end end
end end
end end
......
...@@ -8663,9 +8663,6 @@ msgstr "" ...@@ -8663,9 +8663,6 @@ msgstr ""
msgid "Failed Jobs" msgid "Failed Jobs"
msgstr "" msgstr ""
msgid "Failed create wiki"
msgstr ""
msgid "Failed to add a Zoom meeting" msgid "Failed to add a Zoom meeting"
msgstr "" msgstr ""
...@@ -8705,6 +8702,9 @@ msgstr "" ...@@ -8705,6 +8702,9 @@ msgstr ""
msgid "Failed to create resources" msgid "Failed to create resources"
msgstr "" msgstr ""
msgid "Failed to create wiki"
msgstr ""
msgid "Failed to delete board. Please try again." msgid "Failed to delete board. Please try again."
msgstr "" msgstr ""
......
...@@ -25,11 +25,11 @@ FactoryBot.define do ...@@ -25,11 +25,11 @@ FactoryBot.define do
factory :wiki_page_event do factory :wiki_page_event do
action { Event::CREATED } action { Event::CREATED }
project { @overrides[:wiki_page]&.project || create(:project, :wiki_repo) } project { @overrides[:wiki_page]&.container || create(:project, :wiki_repo) }
target { create(:wiki_page_meta, :for_wiki_page, wiki_page: wiki_page) } target { create(:wiki_page_meta, :for_wiki_page, wiki_page: wiki_page) }
transient do transient do
wiki_page { create(:wiki_page, project: project) } wiki_page { create(:wiki_page, container: project) }
end end
end end
end end
......
...@@ -51,5 +51,11 @@ FactoryBot.define do ...@@ -51,5 +51,11 @@ FactoryBot.define do
trait :owner_subgroup_creation_only do trait :owner_subgroup_creation_only do
subgroup_creation_level { ::Gitlab::Access::OWNER_SUBGROUP_ACCESS} subgroup_creation_level { ::Gitlab::Access::OWNER_SUBGROUP_ACCESS}
end end
trait :wiki_repo do
after(:create) do |group|
raise 'Failed to create wiki repository!' unless group.create_wiki
end
end
end end
end end
# frozen_string_literal: true
FactoryBot.define do
factory :project_wiki do
skip_create
association :project, :wiki_repo
user { project.creator }
initialize_with { new(project, user) }
end
end
...@@ -8,7 +8,8 @@ FactoryBot.define do ...@@ -8,7 +8,8 @@ FactoryBot.define do
title { generate(:wiki_page_title) } title { generate(:wiki_page_title) }
content { 'Content for wiki page' } content { 'Content for wiki page' }
format { 'markdown' } format { 'markdown' }
project { create(:project) } project { association(:project, :wiki_repo) }
container { project }
attrs do attrs do
{ {
title: title, title: title,
...@@ -19,7 +20,7 @@ FactoryBot.define do ...@@ -19,7 +20,7 @@ FactoryBot.define do
end end
page { OpenStruct.new(url_path: 'some-name') } page { OpenStruct.new(url_path: 'some-name') }
wiki { build(:project_wiki, project: project) } wiki { association(:wiki, container: container) }
initialize_with { new(wiki, page) } initialize_with { new(wiki, page) }
...@@ -32,8 +33,6 @@ FactoryBot.define do ...@@ -32,8 +33,6 @@ FactoryBot.define do
end end
trait :with_real_page do trait :with_real_page do
project { create(:project, :repository) }
page do page do
wiki.create_page(title, content) wiki.create_page(title, content)
page_title, page_dir = wiki.page_title_and_dir(title) page_title, page_dir = wiki.page_title_and_dir(title)
...@@ -48,10 +47,10 @@ FactoryBot.define do ...@@ -48,10 +47,10 @@ FactoryBot.define do
trait :for_wiki_page do trait :for_wiki_page do
transient do transient do
wiki_page { create(:wiki_page, project: project) } wiki_page { create(:wiki_page, container: project) }
end end
project { @overrides[:wiki_page]&.project || create(:project) } project { @overrides[:wiki_page]&.container || create(:project) }
title { wiki_page.title } title { wiki_page.title }
initialize_with do initialize_with do
......
# frozen_string_literal: true
FactoryBot.define do
factory :wiki do
transient do
container { association(:project, :wiki_repo) }
user { association(:user) }
end
initialize_with { Wiki.for_container(container, user) }
skip_create
factory :project_wiki do
transient do
project { association(:project, :wiki_repo) }
end
container { project }
end
factory :group_wiki do
container { association(:group, :wiki_repo) }
end
end
end
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
describe EventsHelper do describe EventsHelper do
include Gitlab::Routing
describe '#event_commit_title' do describe '#event_commit_title' do
let(:message) { 'foo & bar ' + 'A' * 70 + '\n' + 'B' * 80 } let(:message) { 'foo & bar ' + 'A' * 70 + '\n' + 'B' * 80 }
......
...@@ -59,8 +59,8 @@ describe Banzai::Pipeline::WikiPipeline do ...@@ -59,8 +59,8 @@ describe Banzai::Pipeline::WikiPipeline do
let(:project_wiki) { ProjectWiki.new(project, double(:user)) } 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')) } 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 root URL' => '',
"when GitLab is hosted at a relative URL" => '/nested/relative/gitlab' }.each do |test_name, relative_url_root| 'when GitLab is hosted at a relative URL' => '/nested/relative/gitlab' }.each do |test_name, relative_url_root|
context test_name do context test_name do
before do before do
allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return(relative_url_root) allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return(relative_url_root)
......
...@@ -52,14 +52,10 @@ describe Gitlab::GitAccessWiki do ...@@ -52,14 +52,10 @@ describe Gitlab::GitAccessWiki do
end end
context 'when the wiki repository does not exist' do context 'when the wiki repository does not exist' do
it 'returns not found' do let(:project) { create(:project) }
wiki_repo = project.wiki.repository
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
FileUtils.rm_rf(wiki_repo.path)
end
# Sanity check for rm_rf it 'returns not found' do
expect(wiki_repo.exists?).to eq(false) expect(project.wiki_repository_exists?).to eq(false)
expect { subject }.to raise_error(Gitlab::GitAccess::NotFoundError, 'A repository for this project does not exist yet.') expect { subject }.to raise_error(Gitlab::GitAccess::NotFoundError, 'A repository for this project does not exist yet.')
end end
......
...@@ -9,7 +9,8 @@ describe Gitlab::RepositoryUrlBuilder do ...@@ -9,7 +9,8 @@ describe Gitlab::RepositoryUrlBuilder do
where(:factory, :path_generator) do where(:factory, :path_generator) do
:project | ->(project) { project.full_path } :project | ->(project) { project.full_path }
:project_snippet | ->(snippet) { "#{snippet.project.full_path}/snippets/#{snippet.id}" } :project_snippet | ->(snippet) { "#{snippet.project.full_path}/snippets/#{snippet.id}" }
:project_wiki | ->(wiki) { "#{wiki.project.full_path}.wiki" } :project_wiki | ->(wiki) { "#{wiki.container.full_path}.wiki" }
:group_wiki | ->(wiki) { "#{wiki.container.full_path}.wiki" }
:personal_snippet | ->(snippet) { "snippets/#{snippet.id}" } :personal_snippet | ->(snippet) { "snippets/#{snippet.id}" }
end end
......
...@@ -23,11 +23,12 @@ describe Gitlab::UrlBuilder do ...@@ -23,11 +23,12 @@ describe Gitlab::UrlBuilder do
:merge_request | ->(merge_request) { "/#{merge_request.project.full_path}/-/merge_requests/#{merge_request.iid}" } :merge_request | ->(merge_request) { "/#{merge_request.project.full_path}/-/merge_requests/#{merge_request.iid}" }
:project_milestone | ->(milestone) { "/#{milestone.project.full_path}/-/milestones/#{milestone.iid}" } :project_milestone | ->(milestone) { "/#{milestone.project.full_path}/-/milestones/#{milestone.iid}" }
:project_snippet | ->(snippet) { "/#{snippet.project.full_path}/snippets/#{snippet.id}" } :project_snippet | ->(snippet) { "/#{snippet.project.full_path}/snippets/#{snippet.id}" }
:project_wiki | ->(wiki) { "/#{wiki.project.full_path}/-/wikis/home" } :project_wiki | ->(wiki) { "/#{wiki.container.full_path}/-/wikis/home" }
:ci_build | ->(build) { "/#{build.project.full_path}/-/jobs/#{build.id}" } :ci_build | ->(build) { "/#{build.project.full_path}/-/jobs/#{build.id}" }
:group | ->(group) { "/groups/#{group.full_path}" } :group | ->(group) { "/groups/#{group.full_path}" }
:group_milestone | ->(milestone) { "/groups/#{milestone.group.full_path}/-/milestones/#{milestone.iid}" } :group_milestone | ->(milestone) { "/groups/#{milestone.group.full_path}/-/milestones/#{milestone.iid}" }
:group_wiki | ->(wiki) { "/groups/#{wiki.container.full_path}/-/wikis/home" }
:user | ->(user) { "/#{user.full_path}" } :user | ->(user) { "/#{user.full_path}" }
:personal_snippet | ->(snippet) { "/snippets/#{snippet.id}" } :personal_snippet | ->(snippet) { "/snippets/#{snippet.id}" }
......
...@@ -25,6 +25,11 @@ describe Group do ...@@ -25,6 +25,11 @@ describe Group do
it { is_expected.to have_many(:clusters).class_name('Clusters::Cluster') } it { is_expected.to have_many(:clusters).class_name('Clusters::Cluster') }
it { is_expected.to have_many(:container_repositories) } it { is_expected.to have_many(:container_repositories) }
it_behaves_like 'model with wiki' do
let(:container) { create(:group, :nested, :wiki_repo) }
let(:container_without_wiki) { create(:group, :nested) }
end
describe '#members & #requesters' do describe '#members & #requesters' do
let(:requester) { create(:user) } let(:requester) { create(:user) }
let(:developer) { create(:user) } let(:developer) { create(:user) }
......
# frozen_string_literal: true
require 'spec_helper'
describe GroupWiki do
it_behaves_like 'wiki model' do
let(:wiki_container) { create(:group, :wiki_repo) }
let(:wiki_container_without_repo) { create(:group) }
before do
wiki_container.add_owner(user)
end
describe '#storage' do
it 'uses the group repository prefix' do
expect(subject.storage.base_dir).to start_with('@groups/')
end
end
describe '#repository_storage' do
it 'returns the default storage' do
expect(subject.repository_storage).to eq('default')
end
end
describe '#hashed_storage?' do
it 'returns true' do
expect(subject.hashed_storage?).to be(true)
end
end
describe '#disk_path' do
it 'returns the repository storage path' do
expect(subject.disk_path).to eq("#{subject.storage.disk_path}.wiki")
end
end
end
end
...@@ -22,5 +22,6 @@ describe PersonalSnippet do ...@@ -22,5 +22,6 @@ describe PersonalSnippet do
let(:stubbed_container) { build_stubbed(:personal_snippet) } let(:stubbed_container) { build_stubbed(:personal_snippet) }
let(:expected_full_path) { "@snippets/#{container.id}" } let(:expected_full_path) { "@snippets/#{container.id}" }
let(:expected_web_url_path) { "snippets/#{container.id}" } let(:expected_web_url_path) { "snippets/#{container.id}" }
let(:expected_repo_url_path) { expected_web_url_path }
end end
end end
...@@ -38,5 +38,6 @@ describe ProjectSnippet do ...@@ -38,5 +38,6 @@ describe ProjectSnippet do
let(:stubbed_container) { build_stubbed(:project_snippet) } let(:stubbed_container) { build_stubbed(:project_snippet) }
let(:expected_full_path) { "#{container.project.full_path}/@snippets/#{container.id}" } let(:expected_full_path) { "#{container.project.full_path}/@snippets/#{container.id}" }
let(:expected_web_url_path) { "#{container.project.full_path}/snippets/#{container.id}" } let(:expected_web_url_path) { "#{container.project.full_path}/snippets/#{container.id}" }
let(:expected_repo_url_path) { expected_web_url_path }
end end
end end
...@@ -118,6 +118,11 @@ describe Project do ...@@ -118,6 +118,11 @@ describe Project do
let(:expected_full_path) { "#{container.namespace.full_path}/somewhere" } let(:expected_full_path) { "#{container.namespace.full_path}/somewhere" }
end end
it_behaves_like 'model with wiki' do
let(:container) { create(:project, :wiki_repo) }
let(:container_without_wiki) { create(:project) }
end
it 'has an inverse relationship with merge requests' do it 'has an inverse relationship with merge requests' do
expect(described_class.reflect_on_association(:merge_requests).has_inverse?).to eq(:target_project) expect(described_class.reflect_on_association(:merge_requests).has_inverse?).to eq(:target_project)
end end
...@@ -263,27 +268,6 @@ describe Project do ...@@ -263,27 +268,6 @@ describe Project do
create(:project) create(:project)
end end
describe 'wiki path conflict' do
context "when the new path has been used by the wiki of other Project" do
it 'has an error on the name attribute' do
new_project = build_stubbed(:project, namespace_id: project.namespace_id, path: "#{project.path}.wiki")
expect(new_project).not_to be_valid
expect(new_project.errors[:name].first).to eq(_('has already been taken'))
end
end
context "when the new wiki path has been used by the path of other Project" do
it 'has an error on the name attribute' do
project_with_wiki_suffix = create(:project, path: 'foo.wiki')
new_project = build_stubbed(:project, namespace_id: project_with_wiki_suffix.namespace_id, path: 'foo')
expect(new_project).not_to be_valid
expect(new_project.errors[:name].first).to eq(_('has already been taken'))
end
end
end
context 'repository storages inclusion' do context 'repository storages inclusion' do
let(:project2) { build(:project, repository_storage: 'missing') } let(:project2) { build(:project, repository_storage: 'missing') }
...@@ -4728,20 +4712,6 @@ describe Project do ...@@ -4728,20 +4712,6 @@ describe Project do
end end
end end
describe '#wiki_repository_exists?' do
it 'returns true when the wiki repository exists' do
project = create(:project, :wiki_repo)
expect(project.wiki_repository_exists?).to eq(true)
end
it 'returns false when the wiki repository does not exist' do
project = create(:project)
expect(project.wiki_repository_exists?).to eq(false)
end
end
describe '#write_repository_config' do describe '#write_repository_config' do
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
......
This diff is collapsed.
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
require "spec_helper" require "spec_helper"
describe WikiPage do describe WikiPage do
let(:project) { create(:project, :wiki_repo) } let_it_be(:user) { create(:user) }
let(:user) { project.owner } let(:container) { create(:project, :wiki_repo) }
let(:wiki) { ProjectWiki.new(project, user) } let(:wiki) { Wiki.for_container(container, user) }
let(:new_page) do let(:new_page) do
described_class.new(wiki).tap do |page| described_class.new(wiki).tap do |page|
...@@ -24,9 +24,9 @@ describe WikiPage do ...@@ -24,9 +24,9 @@ describe WikiPage do
stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => false) stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => false)
end end
def enable_front_matter_for_project def enable_front_matter_for(thing)
stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => { stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => {
thing: project, thing: thing,
enabled: true enabled: true
}) })
end end
...@@ -114,7 +114,8 @@ describe WikiPage do ...@@ -114,7 +114,8 @@ describe WikiPage do
describe '#front_matter' do describe '#front_matter' do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let(:wiki_page) { create(:wiki_page, project: project, content: content) } let(:container) { project }
let(:wiki_page) { create(:wiki_page, container: container, content: content) }
shared_examples 'a page without front-matter' do shared_examples 'a page without front-matter' do
it { expect(wiki_page).to have_attributes(front_matter: {}, content: content) } it { expect(wiki_page).to have_attributes(front_matter: {}, content: content) }
...@@ -153,15 +154,23 @@ describe WikiPage do ...@@ -153,15 +154,23 @@ describe WikiPage do
it_behaves_like 'a page without front-matter' it_behaves_like 'a page without front-matter'
context 'but enabled for the project' do context 'but enabled for the container' do
before do before do
enable_front_matter_for_project enable_front_matter_for(container)
end end
context 'with a project container' do
it_behaves_like 'a page with front-matter'
end
context 'with a group container' do
let(:container) { create(:group) }
it_behaves_like 'a page with front-matter' it_behaves_like 'a page with front-matter'
end end
end end
end end
end
context 'the wiki page does not have front matter' do context 'the wiki page does not have front matter' do
let(:content) { 'My actual content' } let(:content) { 'My actual content' }
...@@ -514,13 +523,21 @@ describe WikiPage do ...@@ -514,13 +523,21 @@ describe WikiPage do
expect([subject, page]).to all(have_attributes(front_matter: be_empty, content: content)) expect([subject, page]).to all(have_attributes(front_matter: be_empty, content: content))
end end
context 'but it is enabled for the project' do context 'but it is enabled for the container' do
before do before do
enable_front_matter_for_project enable_front_matter_for(container)
end end
context 'with a project container' do
it_behaves_like 'able to update front-matter' it_behaves_like 'able to update front-matter'
end end
context 'with a group container' do
let(:container) { create(:group) }
it_behaves_like 'able to update front-matter'
end
end
end end
it 'updates the wiki-page front-matter and content together' do it 'updates the wiki-page front-matter and content together' do
...@@ -812,23 +829,32 @@ describe WikiPage do ...@@ -812,23 +829,32 @@ describe WikiPage do
other_page = create(:wiki_page) other_page = create(:wiki_page)
expect(subject.slug).not_to eq(other_page.slug) expect(subject.slug).not_to eq(other_page.slug)
expect(subject.project).not_to eq(other_page.project) expect(subject.container).not_to eq(other_page.container)
expect(subject).not_to eq(other_page) expect(subject).not_to eq(other_page)
end end
it 'returns false for page with different slug on same project' do it 'returns false for page with different slug on same container' do
other_page = create(:wiki_page, project: subject.project) other_page = create(:wiki_page, container: subject.container)
expect(subject.slug).not_to eq(other_page.slug) expect(subject.slug).not_to eq(other_page.slug)
expect(subject.project).to eq(other_page.project) expect(subject.container).to eq(other_page.container)
expect(subject).not_to eq(other_page) expect(subject).not_to eq(other_page)
end end
it 'returns false for page with the same slug on a different project' do it 'returns false for page with the same slug on a different container of the same type' do
other_page = create(:wiki_page, title: existing_page.slug) other_page = create(:wiki_page, title: existing_page.slug)
expect(subject.slug).to eq(other_page.slug) expect(subject.slug).to eq(other_page.slug)
expect(subject.project).not_to eq(other_page.project) expect(subject.container).not_to eq(other_page.container)
expect(subject).not_to eq(other_page)
end
it 'returns false for page with the same slug on a different container type' do
group = create(:group, name: container.name)
other_page = create(:wiki_page, title: existing_page.slug, container: group)
expect(subject.slug).to eq(other_page.slug)
expect(subject.container).not_to eq(other_page.container)
expect(subject).not_to eq(other_page) expect(subject).not_to eq(other_page)
end end
end end
......
...@@ -5,6 +5,7 @@ RSpec.shared_examples 'model with repository' do ...@@ -5,6 +5,7 @@ RSpec.shared_examples 'model with repository' do
let(:stubbed_container) { raise NotImplementedError } let(:stubbed_container) { raise NotImplementedError }
let(:expected_full_path) { raise NotImplementedError } let(:expected_full_path) { raise NotImplementedError }
let(:expected_web_url_path) { expected_full_path } let(:expected_web_url_path) { expected_full_path }
let(:expected_repo_url_path) { expected_full_path }
describe '#commits_by' do describe '#commits_by' do
let(:commits) { container.repository.commits('HEAD', limit: 3).commits } let(:commits) { container.repository.commits('HEAD', limit: 3).commits }
...@@ -53,19 +54,19 @@ RSpec.shared_examples 'model with repository' do ...@@ -53,19 +54,19 @@ RSpec.shared_examples 'model with repository' do
describe '#url_to_repo' do describe '#url_to_repo' do
it 'returns the SSH URL to the repository' do it 'returns the SSH URL to the repository' do
expect(container.url_to_repo).to eq("#{Gitlab.config.gitlab_shell.ssh_path_prefix}#{expected_web_url_path}.git") expect(container.url_to_repo).to eq(container.ssh_url_to_repo)
end end
end end
describe '#ssh_url_to_repo' do describe '#ssh_url_to_repo' do
it 'returns the SSH URL to the repository' do it 'returns the SSH URL to the repository' do
expect(container.ssh_url_to_repo).to eq(container.url_to_repo) expect(container.ssh_url_to_repo).to eq("#{Gitlab.config.gitlab_shell.ssh_path_prefix}#{expected_repo_url_path}.git")
end end
end end
describe '#http_url_to_repo' do describe '#http_url_to_repo' do
it 'returns the HTTP URL to the repository' do it 'returns the HTTP URL to the repository' do
expect(container.http_url_to_repo).to eq("#{Gitlab.config.gitlab.url}/#{expected_web_url_path}.git") expect(container.http_url_to_repo).to eq("#{Gitlab.config.gitlab.url}/#{expected_repo_url_path}.git")
end end
end end
...@@ -95,12 +96,8 @@ RSpec.shared_examples 'model with repository' do ...@@ -95,12 +96,8 @@ RSpec.shared_examples 'model with repository' do
end end
context 'when the repo exists' do context 'when the repo exists' do
it { expect(container.empty_repo?).to be(false) } it 'returns the empty state of the repository' do
expect(container.empty_repo?).to be(container.repository.empty?)
it 'returns true when repository is empty' do
allow(container.repository).to receive(:empty?).and_return(true)
expect(container.empty_repo?).to be(true)
end end
end end
end end
...@@ -146,15 +143,14 @@ RSpec.shared_examples 'model with repository' do ...@@ -146,15 +143,14 @@ RSpec.shared_examples 'model with repository' do
end end
it 'picks storage from ApplicationSetting' do it 'picks storage from ApplicationSetting' do
expect_next_instance_of(ApplicationSetting) do |instance| expect(Gitlab::CurrentSettings).to receive(:pick_repository_storage).and_return('picked')
expect(instance).to receive(:pick_repository_storage).and_return('picked')
end
expect(subject).to eq('picked') expect(subject).to eq('picked')
end end
it 'picks from the latest available storage', :request_store do it 'picks from the latest available storage', :request_store do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
Gitlab::CurrentSettings.expire_current_application_settings
Gitlab::CurrentSettings.current_application_settings Gitlab::CurrentSettings.current_application_settings
settings = ApplicationSetting.last settings = ApplicationSetting.last
......
# frozen_string_literal: true
RSpec.shared_examples 'model with wiki' do
describe '#create_wiki' do
it 'returns true if the wiki repository already exists' do
expect(container.wiki_repository_exists?).to be(true)
expect(container.create_wiki).to be(true)
end
it 'returns true if the wiki repository was created' do
expect(container_without_wiki.wiki_repository_exists?).to be(false)
expect(container_without_wiki.create_wiki).to be(true)
expect(container_without_wiki.wiki_repository_exists?).to be(true)
end
context 'when the repository cannot be created' do
before do
expect(container.wiki).to receive(:wiki) { raise Wiki::CouldNotCreateWikiError }
end
it 'returns false and adds a validation error' do
expect(container.create_wiki).to be(false)
expect(container.errors[:base]).to contain_exactly('Failed to create wiki')
end
end
end
describe '#wiki_repository_exists?' do
it 'returns true when the wiki repository exists' do
expect(container.wiki_repository_exists?).to eq(true)
end
it 'returns false when the wiki repository does not exist' do
expect(container_without_wiki.wiki_repository_exists?).to eq(false)
end
end
describe 'wiki path conflict' do
context 'when the new path has been used by the wiki of other Project' do
it 'has an error on the name attribute' do
create(:project, namespace: container.parent, path: 'existing')
container.path = 'existing.wiki'
expect(container).not_to be_valid
expect(container.errors[:name].first).to eq(_('has already been taken'))
end
end
context 'when the new wiki path has been used by the path of other Project' do
it 'has an error on the name attribute' do
create(:project, namespace: container.parent, path: 'existing.wiki')
container.path = 'existing'
expect(container).not_to be_valid
expect(container.errors[:name].first).to eq(_('has already been taken'))
end
end
context 'when the new path has been used by the wiki of other Group' do
it 'has an error on the name attribute' do
create(:group, parent: container.parent, path: 'existing')
container.path = 'existing.wiki'
expect(container).not_to be_valid
expect(container.errors[:name].first).to eq(_('has already been taken'))
end
end
context 'when the new wiki path has been used by the path of other Group' do
it 'has an error on the name attribute' do
create(:group, parent: container.parent, path: 'existing.wiki')
container.path = 'existing'
expect(container).not_to be_valid
expect(container.errors[:name].first).to eq(_('has already been taken'))
end
end
end
end
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment