Commit cbb0a680 authored by Dmytro Zaporozhets's avatar Dmytro Zaporozhets

Merge branch 'group-wiki-models' into 'master'

Add group wiki model

See merge request gitlab-org/gitlab!27428
parents e5b265d8 fe5533a7
...@@ -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,
...@@ -1056,16 +1057,6 @@ class Project < ApplicationRecord ...@@ -1056,16 +1057,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
...@@ -1557,10 +1548,6 @@ class Project < ApplicationRecord ...@@ -1557,10 +1548,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?
...@@ -1574,20 +1561,6 @@ class Project < ApplicationRecord ...@@ -1574,20 +1561,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
...@@ -2417,6 +2390,11 @@ class Project < ApplicationRecord ...@@ -2417,6 +2390,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
......
...@@ -8723,9 +8723,6 @@ msgstr "" ...@@ -8723,9 +8723,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 ""
...@@ -8765,6 +8762,9 @@ msgstr "" ...@@ -8765,6 +8762,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') }
...@@ -4716,20 +4700,6 @@ describe Project do ...@@ -4716,20 +4700,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) }
......
# frozen_string_literal: true # frozen_string_literal: true
require "spec_helper" require 'spec_helper'
describe ProjectWiki do describe ProjectWiki do
let(:user) { create(:user, :commit_email) } it_behaves_like 'wiki model' do
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } let(:wiki_container) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:repository) { project.repository } let(:wiki_container_without_repo) { create(:project, namespace: user.namespace) }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project_wiki) { described_class.new(project, user) }
let(:raw_repository) { Gitlab::Git::Repository.new(project.repository_storage, subject.disk_path + '.git', 'foo', 'group/project.wiki') }
let(:commit) { project_wiki.repository.head_commit }
subject { project_wiki } it { is_expected.to delegate_method(:storage).to(:container) }
it { is_expected.to delegate_method(:repository_storage).to(:container) }
it { is_expected.to delegate_method(:hashed_storage?).to(:container) }
it { is_expected.to delegate_method(:repository_storage).to :project } describe '#disk_path' do
it { is_expected.to delegate_method(:hashed_storage?).to :project } it 'returns the repository storage path' do
expect(subject.disk_path).to eq("#{subject.container.disk_path}.wiki")
describe "#full_path" do
it "returns the project path with namespace with the .wiki extension" do
expect(subject.full_path).to eq(project.full_path + '.wiki')
end
it 'returns the same value as #full_path' do
expect(subject.full_path).to eq(subject.full_path)
end
end
describe '#web_url' do
it 'returns the full web URL to the wiki' do
expect(subject.web_url).to eq(Gitlab::UrlBuilder.build(subject))
end
end
describe "#url_to_repo" do
it "returns the correct ssh url to the repo" do
expect(subject.url_to_repo).to eq(Gitlab::RepositoryUrlBuilder.build(subject.repository.full_path, protocol: :ssh))
end
end
describe "#ssh_url_to_repo" do
it "equals #url_to_repo" do
expect(subject.ssh_url_to_repo).to eq(subject.url_to_repo)
end
end
describe "#http_url_to_repo" do
it "returns the correct http url to the repo" do
expect(subject.http_url_to_repo).to eq(Gitlab::RepositoryUrlBuilder.build(subject.repository.full_path, protocol: :http))
end
end
describe "#wiki_base_path" do
it "returns the wiki base path" do
wiki_base_path = "#{Gitlab.config.gitlab.relative_url_root}/#{project.full_path}/-/wikis"
expect(subject.wiki_base_path).to eq(wiki_base_path)
end
end
describe "#wiki" do
it "contains a Gitlab::Git::Wiki instance" do
expect(subject.wiki).to be_a Gitlab::Git::Wiki
end
it "creates a new wiki repo if one does not yet exist" do
expect(project_wiki.create_page("index", "test content")).to be_truthy
end
it "creates a new wiki repo with a default commit message" do
expect(project_wiki.create_page("index", "test content", :markdown, "")).to be_truthy
page = project_wiki.find_page('index')
expect(page.last_version.message).to eq("#{user.username} created page: index")
end
it "raises CouldNotCreateWikiError if it can't create the wiki repository" do
# Create a fresh project which will not have a wiki
project_wiki = described_class.new(create(:project), user)
expect(project_wiki.repository).to receive(:create_if_not_exists) { false }
expect { project_wiki.send(:wiki) }.to raise_exception(ProjectWiki::CouldNotCreateWikiError)
end
end
describe "#empty?" do
context "when the wiki repository is empty" do
describe '#empty?' do
subject { super().empty? }
it { is_expected.to be_truthy }
end
end
context "when the wiki has pages" do
before do
project_wiki.create_page("index", "This is an awesome new Gollum Wiki")
project_wiki.create_page("another-page", "This is another page")
end
describe '#empty?' do
subject { super().empty? }
it { is_expected.to be_falsey }
it 'only instantiates a Wiki page once' do
expect(WikiPage).to receive(:new).once.and_call_original
subject
end
end
end
end
describe "#list_pages" do
let(:wiki_pages) { subject.list_pages }
before do
create_page("index", "This is an index")
create_page("index2", "This is an index2")
create_page("an index3", "This is an index3")
end
after do
wiki_pages.each do |wiki_page|
destroy_page(wiki_page.page)
end
end
it "returns an array of WikiPage instances" do
expect(wiki_pages.first).to be_a WikiPage
end
it 'does not load WikiPage content by default' do
wiki_pages.each do |page|
expect(page.content).to be_empty
end
end
it 'returns all pages by default' do
expect(wiki_pages.count).to eq(3)
end
context "with limit option" do
it 'returns limited set of pages' do
expect(subject.list_pages(limit: 1).count).to eq(1)
end
end
context "with sorting options" do
it 'returns pages sorted by title by default' do
pages = ['an index3', 'index', 'index2']
expect(subject.list_pages.map(&:title)).to eq(pages)
expect(subject.list_pages(direction: "desc").map(&:title)).to eq(pages.reverse)
end
it 'returns pages sorted by created_at' do
pages = ['index', 'index2', 'an index3']
expect(subject.list_pages(sort: 'created_at').map(&:title)).to eq(pages)
expect(subject.list_pages(sort: 'created_at', direction: "desc").map(&:title)).to eq(pages.reverse)
end
end
context "with load_content option" do
let(:pages) { subject.list_pages(load_content: true) }
it 'loads WikiPage content' do
expect(pages.first.content).to eq("This is an index3")
expect(pages.second.content).to eq("This is an index")
expect(pages.third.content).to eq("This is an index2")
end
end
end
describe "#find_page" do
before do
create_page("index page", "This is an awesome Gollum Wiki")
end
after do
subject.list_pages.each { |page| destroy_page(page.page) }
end
it "returns the latest version of the page if it exists" do
page = subject.find_page("index page")
expect(page.title).to eq("index page")
end
it "returns nil if the page does not exist" do
expect(subject.find_page("non-existent")).to eq(nil)
end
it "can find a page by slug" do
page = subject.find_page("index-page")
expect(page.title).to eq("index page")
end
it "returns a WikiPage instance" do
page = subject.find_page("index page")
expect(page).to be_a WikiPage
end
context 'pages with multibyte-character title' do
before do
create_page("autre pagé", "C'est un génial Gollum Wiki")
end
it "can find a page by slug" do
page = subject.find_page("autre pagé")
expect(page.title).to eq("autre pagé")
end
end
context 'pages with invalidly-encoded content' do
before do
create_page("encoding is fun", "f\xFCr".b)
end
it "can find the page" do
page = subject.find_page("encoding is fun")
expect(page.content).to eq("fr")
end end
end end
end
describe '#find_sidebar' do
before do
create_page(described_class::SIDEBAR, 'This is an awesome Sidebar')
end
after do
subject.list_pages.each { |page| destroy_page(page.page) }
end
it 'finds the page defined as _sidebar' do
page = subject.find_page('_sidebar')
expect(page.content).to eq('This is an awesome Sidebar')
end
end
describe '#find_file' do describe '#update_container_activity' do
let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) } it 'updates project activity' do
wiki_container.update!(
last_activity_at: nil,
last_repository_updated_at: nil
)
before do subject.create_page('Test Page', 'This is content')
subject.wiki # Make sure the wiki repo exists wiki_container.reload
repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do expect(wiki_container.last_activity_at).to be_within(1.minute).of(Time.now)
subject.repository.path_to_repo expect(wiki_container.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end end
BareRepoOperations.new(repo_path).commit_file(image, 'image.png')
end
it 'returns the latest version of the file if it exists' do
file = subject.find_file('image.png')
expect(file.mime_type).to eq('image/png')
end
it 'returns nil if the page does not exist' do
expect(subject.find_file('non-existent')).to eq(nil)
end
it 'returns a Gitlab::Git::WikiFile instance' do
file = subject.find_file('image.png')
expect(file).to be_a Gitlab::Git::WikiFile
end
it 'returns the whole file' do
file = subject.find_file('image.png')
image.rewind
expect(file.raw_data.b).to eq(image.read.b)
end
end
describe "#create_page" do
after do
destroy_page(subject.list_pages.first.page)
end
it "creates a new wiki page" do
expect(subject.create_page("test page", "this is content")).not_to eq(false)
expect(subject.list_pages.count).to eq(1)
end
it "returns false when a duplicate page exists" do
subject.create_page("test page", "content")
expect(subject.create_page("test page", "content")).to eq(false)
end end
it "stores an error message when a duplicate page exists" do
2.times { subject.create_page("test page", "content") }
expect(subject.error_message).to match(/Duplicate page:/)
end
it "sets the correct commit message" do
subject.create_page("test page", "some content", :markdown, "commit message")
expect(subject.list_pages.first.page.version.message).to eq("commit message")
end
it 'sets the correct commit email' do
subject.create_page('test page', 'content')
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
it 'updates project activity' do
subject.create_page('Test Page', 'This is content')
project.reload
expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end
end
describe "#update_page" do
before do
create_page("update-page", "some content")
@gitlab_git_wiki_page = subject.wiki.page(title: "update-page")
subject.update_page(
@gitlab_git_wiki_page,
content: "some other content",
format: :markdown,
message: "updated page"
)
@page = subject.list_pages(load_content: true).first.page
end
after do
destroy_page(@page)
end
it "updates the content of the page" do
expect(@page.raw_data).to eq("some other content")
end
it "sets the correct commit message" do
expect(@page.version.message).to eq("updated page")
end
it 'sets the correct commit email' do
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
it 'updates project activity' do
subject.update_page(
@gitlab_git_wiki_page,
content: 'Yet more content',
format: :markdown,
message: 'Updated page again'
)
project.reload
expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end
end
describe "#delete_page" do
before do
create_page("index", "some content")
@page = subject.wiki.page(title: "index")
end
it "deletes the page" do
subject.delete_page(@page)
expect(subject.list_pages.count).to eq(0)
end
it 'sets the correct commit email' do
subject.delete_page(@page)
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
it 'updates project activity' do
subject.delete_page(@page)
project.reload
expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end
end
describe '#ensure_repository' do
let(:project) { create(:project) }
it 'creates the repository if it not exist' do
expect(raw_repository.exists?).to eq(false)
subject.ensure_repository
expect(raw_repository.exists?).to eq(true)
end
it 'does not create the repository if it exists' do
subject.wiki
expect(raw_repository.exists?).to eq(true)
expect(subject).not_to receive(:create_repo!)
subject.ensure_repository
end
end
describe '#hook_attrs' do
it 'returns a hash with values' do
expect(subject.hook_attrs).to be_a Hash
expect(subject.hook_attrs.keys).to contain_exactly(:web_url, :git_ssh_url, :git_http_url, :path_with_namespace, :default_branch)
end
end
private
def create_temp_repo(path)
FileUtils.mkdir_p path
system(*%W(#{Gitlab.config.git.bin_path} init --quiet --bare -- #{path}))
end
def remove_temp_repo(path)
FileUtils.rm_rf path
end
def commit_details
Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.commit_email, "test commit")
end
def create_page(name, content)
subject.wiki.write_page(name, :markdown, content, commit_details)
end
def destroy_page(page)
subject.delete_page(page, "test commit")
end end
end end
...@@ -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,12 +154,20 @@ describe WikiPage do ...@@ -153,12 +154,20 @@ 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
it_behaves_like 'a page with front-matter' 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'
end
end end
end end
end end
...@@ -514,12 +523,20 @@ describe WikiPage do ...@@ -514,12 +523,20 @@ 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
it_behaves_like 'able to update front-matter' context 'with a project container' do
it_behaves_like 'able to update front-matter'
end
context 'with a group container' do
let(:container) { create(:group) }
it_behaves_like 'able to update front-matter'
end
end end
end end
...@@ -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
# frozen_string_literal: true
RSpec.shared_examples 'wiki model' do
let_it_be(:user) { create(:user, :commit_email) }
let(:wiki_container) { raise NotImplementedError }
let(:wiki_container_without_repo) { raise NotImplementedError }
let(:wiki) { described_class.new(wiki_container, user) }
let(:commit) { subject.repository.head_commit }
subject { wiki }
it_behaves_like 'model with repository' do
let(:container) { wiki }
let(:stubbed_container) { described_class.new(wiki_container_without_repo, user) }
let(:expected_full_path) { "#{container.container.full_path}.wiki" }
let(:expected_web_url_path) { "#{container.container.web_url(only_path: true).sub(%r{^/}, '')}/-/wikis/home" }
end
describe '#repository' do
it 'returns a wiki repository' do
expect(subject.repository.repo_type).to be_wiki
end
end
describe '#full_path' do
it 'returns the container path with the .wiki extension' do
expect(subject.full_path).to eq(wiki_container.full_path + '.wiki')
end
end
describe '#wiki_base_path' do
it 'returns the wiki base path' do
expect(subject.wiki_base_path).to eq("#{wiki_container.web_url(only_path: true)}/-/wikis")
end
end
describe '#wiki' do
it 'contains a Gitlab::Git::Wiki instance' do
expect(subject.wiki).to be_a Gitlab::Git::Wiki
end
it 'creates a new wiki repo if one does not yet exist' do
expect(subject.create_page('index', 'test content')).to be_truthy
end
it 'creates a new wiki repo with a default commit message' do
expect(subject.create_page('index', 'test content', :markdown, '')).to be_truthy
page = subject.find_page('index')
expect(page.last_version.message).to eq("#{user.username} created page: index")
end
context 'when the repository cannot be created' do
let(:wiki_container) { wiki_container_without_repo }
before do
expect(subject.repository).to receive(:create_if_not_exists) { false }
end
it 'raises CouldNotCreateWikiError' do
expect { subject.wiki }.to raise_exception(Wiki::CouldNotCreateWikiError)
end
end
end
describe '#empty?' do
context 'when the wiki repository is empty' do
it 'returns true' do
expect(subject.empty?).to be(true)
end
end
context 'when the wiki has pages' do
before do
subject.create_page('index', 'This is an awesome new Gollum Wiki')
subject.create_page('another-page', 'This is another page')
end
describe '#empty?' do
it 'returns false' do
expect(subject.empty?).to be(false)
end
it 'only instantiates a Wiki page once' do
expect(WikiPage).to receive(:new).once.and_call_original
subject.empty?
end
end
end
end
describe '#list_pages' do
let(:wiki_pages) { subject.list_pages }
before do
create_page('index', 'This is an index')
create_page('index2', 'This is an index2')
create_page('an index3', 'This is an index3')
end
it 'returns an array of WikiPage instances' do
expect(wiki_pages.first).to be_a WikiPage
end
it 'does not load WikiPage content by default' do
wiki_pages.each do |page|
expect(page.content).to be_empty
end
end
it 'returns all pages by default' do
expect(wiki_pages.count).to eq(3)
end
context 'with limit option' do
it 'returns limited set of pages' do
expect(subject.list_pages(limit: 1).count).to eq(1)
end
end
context 'with sorting options' do
it 'returns pages sorted by title by default' do
pages = ['an index3', 'index', 'index2']
expect(subject.list_pages.map(&:title)).to eq(pages)
expect(subject.list_pages(direction: 'desc').map(&:title)).to eq(pages.reverse)
end
it 'returns pages sorted by created_at' do
pages = ['index', 'index2', 'an index3']
expect(subject.list_pages(sort: 'created_at').map(&:title)).to eq(pages)
expect(subject.list_pages(sort: 'created_at', direction: 'desc').map(&:title)).to eq(pages.reverse)
end
end
context 'with load_content option' do
let(:pages) { subject.list_pages(load_content: true) }
it 'loads WikiPage content' do
expect(pages.first.content).to eq('This is an index3')
expect(pages.second.content).to eq('This is an index')
expect(pages.third.content).to eq('This is an index2')
end
end
end
describe '#find_page' do
before do
create_page('index page', 'This is an awesome Gollum Wiki')
end
it 'returns the latest version of the page if it exists' do
page = subject.find_page('index page')
expect(page.title).to eq('index page')
end
it 'returns nil if the page does not exist' do
expect(subject.find_page('non-existent')).to eq(nil)
end
it 'can find a page by slug' do
page = subject.find_page('index-page')
expect(page.title).to eq('index page')
end
it 'returns a WikiPage instance' do
page = subject.find_page('index page')
expect(page).to be_a WikiPage
end
context 'pages with multibyte-character title' do
before do
create_page('autre pagé', "C'est un génial Gollum Wiki")
end
it 'can find a page by slug' do
page = subject.find_page('autre pagé')
expect(page.title).to eq('autre pagé')
end
end
context 'pages with invalidly-encoded content' do
before do
create_page('encoding is fun', "f\xFCr".b)
end
it 'can find the page' do
page = subject.find_page('encoding is fun')
expect(page.content).to eq('fr')
end
end
end
describe '#find_sidebar' do
before do
create_page(described_class::SIDEBAR, 'This is an awesome Sidebar')
end
it 'finds the page defined as _sidebar' do
page = subject.find_page('_sidebar')
expect(page.content).to eq('This is an awesome Sidebar')
end
end
describe '#find_file' do
let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) }
before do
subject.wiki # Make sure the wiki repo exists
subject.repository.create_file(user, 'image.png', image, branch_name: subject.default_branch, message: 'add image')
end
it 'returns the latest version of the file if it exists' do
file = subject.find_file('image.png')
expect(file.mime_type).to eq('image/png')
end
it 'returns nil if the page does not exist' do
expect(subject.find_file('non-existent')).to eq(nil)
end
it 'returns a Gitlab::Git::WikiFile instance' do
file = subject.find_file('image.png')
expect(file).to be_a Gitlab::Git::WikiFile
end
it 'returns the whole file' do
file = subject.find_file('image.png')
image.rewind
expect(file.raw_data.b).to eq(image.read.b)
end
end
describe '#create_page' do
it 'creates a new wiki page' do
expect(subject.create_page('test page', 'this is content')).not_to eq(false)
expect(subject.list_pages.count).to eq(1)
end
it 'returns false when a duplicate page exists' do
subject.create_page('test page', 'content')
expect(subject.create_page('test page', 'content')).to eq(false)
end
it 'stores an error message when a duplicate page exists' do
2.times { subject.create_page('test page', 'content') }
expect(subject.error_message).to match(/Duplicate page:/)
end
it 'sets the correct commit message' do
subject.create_page('test page', 'some content', :markdown, 'commit message')
expect(subject.list_pages.first.page.version.message).to eq('commit message')
end
it 'sets the correct commit email' do
subject.create_page('test page', 'content')
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
it 'updates container activity' do
expect(subject).to receive(:update_container_activity)
subject.create_page('Test Page', 'This is content')
end
end
describe '#update_page' do
before do
create_page('update-page', 'some content')
@gitlab_git_wiki_page = subject.wiki.page(title: 'update-page')
subject.update_page(
@gitlab_git_wiki_page,
content: 'some other content',
format: :markdown,
message: 'updated page'
)
@page = subject.list_pages(load_content: true).first.page
end
it 'updates the content of the page' do
expect(@page.raw_data).to eq('some other content')
end
it 'sets the correct commit message' do
expect(@page.version.message).to eq('updated page')
end
it 'sets the correct commit email' do
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
it 'updates container activity' do
expect(subject).to receive(:update_container_activity)
subject.update_page(
@gitlab_git_wiki_page,
content: 'Yet more content',
format: :markdown,
message: 'Updated page again'
)
end
end
describe '#delete_page' do
before do
create_page('index', 'some content')
@page = subject.wiki.page(title: 'index')
end
it 'deletes the page' do
subject.delete_page(@page)
expect(subject.list_pages.count).to eq(0)
end
it 'sets the correct commit email' do
subject.delete_page(@page)
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
it 'updates container activity' do
expect(subject).to receive(:update_container_activity)
subject.delete_page(@page)
end
end
describe '#ensure_repository' do
context 'if the repository exists' do
it 'does not create the repository' do
expect(subject.repository.exists?).to eq(true)
expect(subject.repository.raw).not_to receive(:create_repository)
subject.ensure_repository
end
end
context 'if the repository does not exist' do
let(:wiki_container) { wiki_container_without_repo }
it 'creates the repository' do
expect(subject.repository.exists?).to eq(false)
subject.ensure_repository
expect(subject.repository.exists?).to eq(true)
end
end
end
describe '#hook_attrs' do
it 'returns a hash with values' do
expect(subject.hook_attrs).to be_a Hash
expect(subject.hook_attrs.keys).to contain_exactly(:web_url, :git_ssh_url, :git_http_url, :path_with_namespace, :default_branch)
end
end
private
def create_temp_repo(path)
FileUtils.mkdir_p path
system(*%W(#{Gitlab.config.git.bin_path} init --quiet --bare -- #{path}))
end
def remove_temp_repo(path)
FileUtils.rm_rf path
end
def commit_details
Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.commit_email, 'test commit')
end
def create_page(name, content)
subject.wiki.write_page(name, :markdown, content, commit_details)
end
end
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