Commit 00dff848 authored by Markus Koller's avatar Markus Koller Committed by Douglas Barbosa Alexandre

Use Wiki instance as repository container

Before we started working on group wikis, `ProjectWiki` used a `Project`
instance as the container of its `Repository` instance, so for group
wikis we did the same with `Group`.

This initially made sense and also mostly aligned with the semantics for
`Repository#container`, but while working on wiki diffing [1] we noticed
that the `Commit` and `Blob` classes sometimes use
`container#repository`, which breaks some assumptions and also causes
redundant Gitaly calls to the project repository when diffing wikis.

Refactoring those classes is a lot riskier and would affect other
features too, so in this commit we're instead changing the
`Repository#container` to be the wiki instance, rather than the project
or group. This generally seems to make sense anyway, and only needs some
small adjustments.

To satisfy the interface for `Repository#container`, we need to add
or tweak some methods:

- `Wiki.find_by_id`
- `Wiki#id`
- `Wiki#to_global_id`

We also still need to be able to resolve wiki repositories from their
containers, this is handled in the repository resolver for
`Gitlab::GlRepository::WIKI`.

[1] https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35330
parent 6b19d505
...@@ -71,6 +71,10 @@ module HasRepository ...@@ -71,6 +71,10 @@ module HasRepository
raise NotImplementedError raise NotImplementedError
end end
def lfs_enabled?
false
end
def empty_repo? def empty_repo?
repository.empty? repository.empty?
end end
......
...@@ -35,6 +35,7 @@ class Project < ApplicationRecord ...@@ -35,6 +35,7 @@ class Project < ApplicationRecord
include Integration include Integration
include EachBatch include EachBatch
extend Gitlab::Cache::RequestCache extend Gitlab::Cache::RequestCache
extend Gitlab::Utils::Override
extend Gitlab::ConfigHelper extend Gitlab::ConfigHelper
...@@ -849,6 +850,7 @@ class Project < ApplicationRecord ...@@ -849,6 +850,7 @@ class Project < ApplicationRecord
end end
end end
override :lfs_enabled?
def lfs_enabled? def lfs_enabled?
return namespace.lfs_enabled? if self[:lfs_enabled].nil? return namespace.lfs_enabled? if self[:lfs_enabled].nil?
......
# frozen_string_literal: true # frozen_string_literal: true
class ProjectWiki < Wiki class ProjectWiki < Wiki
self.container_class = Project
alias_method :project, :container alias_method :project, :container
# Project wikis are tied to the main project storage # Project wikis are tied to the main project storage
delegate :storage, :repository_storage, :hashed_storage?, to: :container delegate :storage, :repository_storage, :hashed_storage?, :lfs_enabled?, to: :container
override :disk_path override :disk_path
def disk_path(*args, &block) def disk_path(*args, &block)
......
...@@ -26,6 +26,7 @@ class Repository ...@@ -26,6 +26,7 @@ class Repository
delegate :ref_name_for_sha, to: :raw_repository delegate :ref_name_for_sha, to: :raw_repository
delegate :bundle_to_disk, to: :raw_repository delegate :bundle_to_disk, to: :raw_repository
delegate :lfs_enabled?, to: :container
CreateTreeError = Class.new(StandardError) CreateTreeError = Class.new(StandardError)
AmbiguousRefError = Class.new(StandardError) AmbiguousRefError = Class.new(StandardError)
...@@ -1142,21 +1143,10 @@ class Repository ...@@ -1142,21 +1143,10 @@ class Repository
end end
def project def project
if repo_type.snippet?
container.project
elsif container.is_a?(Project)
container
end
end
# TODO: pass this in directly to `Blob` rather than delegating it to here
#
# https://gitlab.com/gitlab-org/gitlab/-/issues/201886
def lfs_enabled?
if container.is_a?(Project) if container.is_a?(Project)
container.lfs_enabled? container
else else
false # LFS is not supported for snippet or group repositories container.try(:project)
end end
end end
......
...@@ -4,6 +4,7 @@ class Wiki ...@@ -4,6 +4,7 @@ class Wiki
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
include HasRepository include HasRepository
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include GlobalID::Identification
MARKUPS = { # rubocop:disable Style/MultilineIfModifier MARKUPS = { # rubocop:disable Style/MultilineIfModifier
'Markdown' => :markdown, 'Markdown' => :markdown,
...@@ -28,14 +29,46 @@ class Wiki ...@@ -28,14 +29,46 @@ class Wiki
# an operation fails. # an operation fails.
attr_reader :error_message attr_reader :error_message
def self.for_container(container, user = nil) # Support run_after_commit callbacks, since we don't have a DB record
# we delegate to the container.
delegate :run_after_commit, to: :container
class << self
attr_accessor :container_class
def for_container(container, user = nil)
"#{container.class.name}Wiki".constantize.new(container, user) "#{container.class.name}Wiki".constantize.new(container, user)
end end
# This is needed to support repository lookup through Gitlab::GlRepository::Identifier
def find_by_id(container_id)
container_class.find_by_id(container_id)&.wiki
end
end
def initialize(container, user = nil) def initialize(container, user = nil)
raise ArgumentError, "user must be a User, got #{user.class}" if user && !user.is_a?(User)
@container = container @container = container
@user = user @user = user
raise ArgumentError, "user must be a User, got #{user.class}" if user && !user.is_a?(User) end
def ==(other)
other.is_a?(self.class) && container == other.container
end
# This is needed in:
# - Storage::Hashed
# - Gitlab::GlRepository::RepoType#identifier_for_container
#
# We also need an `#id` to support `build_stubbed` in tests, where the
# value doesn't matter.
#
# NOTE: Wikis don't have a DB record, so this ID can be the same
# for two wikis in different containers and should not be expected to
# be unique. Use `to_global_id` instead if you need a unique ID.
def id
container.id
end end
def path def path
...@@ -183,7 +216,7 @@ class Wiki ...@@ -183,7 +216,7 @@ class Wiki
override :repository override :repository
def repository def repository
@repository ||= Gitlab::GlRepository::WIKI.repository_for(container) @repository ||= Gitlab::GlRepository::WIKI.repository_for(self)
end end
def repository_storage def repository_storage
...@@ -198,7 +231,6 @@ class Wiki ...@@ -198,7 +231,6 @@ class Wiki
def full_path def full_path
container.full_path + '.wiki' container.full_path + '.wiki'
end 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 # @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 alias_method :path_with_namespace, :full_path
......
# frozen_string_literal: true
class WikiPolicy < ::BasePolicy
# Wiki policies are delegated to their container objects (Project or Group)
delegate { subject.container }
end
...@@ -24,7 +24,7 @@ class PostReceive # rubocop:disable Scalability/IdempotentWorker ...@@ -24,7 +24,7 @@ class PostReceive # rubocop:disable Scalability/IdempotentWorker
post_received = Gitlab::GitPostReceive.new(container, identifier, changes, push_options) post_received = Gitlab::GitPostReceive.new(container, identifier, changes, push_options)
if repo_type.wiki? if repo_type.wiki?
process_wiki_changes(post_received, container.wiki) process_wiki_changes(post_received, container)
elsif repo_type.project? elsif repo_type.project?
process_project_changes(post_received, container) process_project_changes(post_received, container)
elsif repo_type.snippet? elsif repo_type.snippet?
......
...@@ -5,24 +5,24 @@ module EE ...@@ -5,24 +5,24 @@ module EE
include ::ProjectsHelper include ::ProjectsHelper
include ::ApplicationSettingsHelper include ::ApplicationSettingsHelper
def geo_primary_web_url(project_or_wiki) def geo_primary_web_url(container)
File.join(::Gitlab::Geo.primary_node.url, project_or_wiki.full_path) File.join(::Gitlab::Geo.primary_node.url, container.full_path)
end end
def geo_primary_ssh_url_to_repo(project_or_wiki) def geo_primary_ssh_url_to_repo(container)
"#{::Gitlab::Geo.primary_node.clone_url_prefix}#{project_or_wiki.full_path}.git" "#{::Gitlab::Geo.primary_node.clone_url_prefix}#{container.full_path}.git"
end end
def geo_primary_http_url_to_repo(project_or_wiki) def geo_primary_http_url_to_repo(container)
geo_primary_web_url(project_or_wiki) + '.git' geo_primary_web_url(container) + '.git'
end end
def geo_primary_default_url_to_repo(project_or_wiki) def geo_primary_default_url_to_repo(container)
case default_clone_protocol case default_clone_protocol
when 'ssh' when 'ssh'
geo_primary_ssh_url_to_repo(project_or_wiki) geo_primary_ssh_url_to_repo(container)
else else
geo_primary_http_url_to_repo(project_or_wiki) geo_primary_http_url_to_repo(container)
end end
end end
......
# frozen_string_literal: true # frozen_string_literal: true
class GroupWiki < Wiki class GroupWiki < Wiki
self.container_class = ::Group
alias_method :group, :container alias_method :group, :container
override :create_wiki_repository override :create_wiki_repository
......
...@@ -10,12 +10,6 @@ module EE ...@@ -10,12 +10,6 @@ module EE
GEO_SERVER_DOCS_URL = 'https://docs.gitlab.com/ee/administration/geo/replication/using_a_geo_server.html'.freeze GEO_SERVER_DOCS_URL = 'https://docs.gitlab.com/ee/administration/geo/replication/using_a_geo_server.html'.freeze
protected
def project_or_wiki
project
end
private private
def geo_custom_action def geo_custom_action
...@@ -67,18 +61,18 @@ module EE ...@@ -67,18 +61,18 @@ module EE
def geo_primary_url_to_repo def geo_primary_url_to_repo
case protocol case protocol
when 'ssh' when 'ssh'
geo_primary_ssh_url_to_repo(project_or_wiki) geo_primary_ssh_url_to_repo(container)
else else
geo_primary_http_url_to_repo(project_or_wiki) geo_primary_http_url_to_repo(container)
end end
end end
def primary_http_repo_url def primary_http_repo_url
geo_primary_http_url_to_repo(project_or_wiki) geo_primary_http_url_to_repo(container)
end end
def primary_ssh_url_to_repo def primary_ssh_url_to_repo
geo_primary_ssh_url_to_repo(project_or_wiki) geo_primary_ssh_url_to_repo(container)
end end
def current_replication_lag_message def current_replication_lag_message
......
...@@ -25,11 +25,13 @@ module EE ...@@ -25,11 +25,13 @@ module EE
end end
def group? def group?
container.is_a?(Group) # Strict nil check, to avoid any surprises with Object#present?
# which can delegate to #empty?
!group.nil?
end end
def group def group
container if group? container if container.is_a?(::Group)
end end
protected protected
......
...@@ -12,9 +12,9 @@ module EE ...@@ -12,9 +12,9 @@ module EE
no_group_repo: 'A repository for this group wiki does not exist yet.' no_group_repo: 'A repository for this group wiki does not exist yet.'
}.freeze }.freeze
override :project? override :group
def project? def group
!group? container.group if container.is_a?(GroupWiki)
end end
override :check_container! override :check_container!
...@@ -53,15 +53,11 @@ module EE ...@@ -53,15 +53,11 @@ module EE
def can_read_group? def can_read_group?
if user if user
user.can?(:read_group, container) user.can?(:read_group, group)
else else
Guest.can?(:read_group, container) Guest.can?(:read_group, group)
end end
end end
def project_or_wiki
container.wiki
end
end end
end end
end end
# frozen_string_literal: true
module EE
module Gitlab
module GlRepository
module RepoType
extend ::Gitlab::Utils::Override
override :identifier_for_container
def identifier_for_container(container)
if container.is_a?(GroupWiki)
"group-#{container.id}-#{name}"
else
super
end
end
end
end
end
end
...@@ -5,26 +5,26 @@ require 'spec_helper' ...@@ -5,26 +5,26 @@ require 'spec_helper'
RSpec.describe Gitlab::GitAccessWiki do RSpec.describe Gitlab::GitAccessWiki do
include WikiHelpers include WikiHelpers
let(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo) } let_it_be(:project) { create(:project, :wiki_repo) }
let(:wiki) { create(:project_wiki, project: project) }
let(:changes) { ['6f6d7e7ed 570e7b2ab refs/heads/master'] } let(:changes) { ['6f6d7e7ed 570e7b2ab refs/heads/master'] }
let(:authentication_abilities) { %i[read_project download_code push_code] } let(:authentication_abilities) { %i[read_project download_code push_code] }
let(:redirected_path) { nil } let(:redirected_path) { nil }
let(:access) { described_class.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) } let(:access) do
described_class.new(user, wiki, 'web',
authentication_abilities: authentication_abilities,
redirected_path: redirected_path)
end
before do before do
stub_group_wikis(true) stub_group_wikis(true)
end end
describe 'group wiki access' do describe 'group wiki access' do
let_it_be(:group, reload: true) { create(:group, :private, :wiki_repo) } let_it_be(:group) { create(:group, :private, :wiki_repo) }
let(:wiki) { create(:group_wiki, group: group) }
let(:access) do
described_class.new(user, group, 'web',
authentication_abilities: authentication_abilities,
redirected_path: redirected_path)
end
describe '#push_access_check' do describe '#push_access_check' do
subject { access.check('git-receive-pack', changes) } subject { access.check('git-receive-pack', changes) }
...@@ -72,7 +72,9 @@ RSpec.describe Gitlab::GitAccessWiki do ...@@ -72,7 +72,9 @@ RSpec.describe Gitlab::GitAccessWiki do
end end
context 'when the wiki repository does not exist' do context 'when the wiki repository does not exist' do
let(:group) { create(:group) } before do
allow(wiki.repository).to receive(:exists?).and_return(false)
end
it_behaves_like 'not-found git access' do it_behaves_like 'not-found git access' do
let(:message) { 'A repository for this group wiki does not exist yet.' } let(:message) { 'A repository for this group wiki does not exist yet.' }
......
...@@ -3,14 +3,14 @@ ...@@ -3,14 +3,14 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::GlRepository::Identifier do RSpec.describe Gitlab::GlRepository::Identifier do
let_it_be(:group) { create(:group) }
# GitLab Starter feature # GitLab Starter feature
context 'group wiki' do context 'group wiki' do
let_it_be(:wiki) { create(:group_wiki) }
it_behaves_like 'parsing gl_repository identifier' do it_behaves_like 'parsing gl_repository identifier' do
let(:record_id) { group.id } let(:record_id) { wiki.group.id }
let(:identifier) { "group-#{record_id}-wiki" } let(:identifier) { "group-#{record_id}-wiki" }
let(:expected_container) { group } let(:expected_container) { wiki }
let(:expected_type) { Gitlab::GlRepository::WIKI } let(:expected_type) { Gitlab::GlRepository::WIKI }
end end
end end
......
...@@ -5,14 +5,14 @@ require 'spec_helper' ...@@ -5,14 +5,14 @@ require 'spec_helper'
RSpec.describe Gitlab::GlRepository::RepoType do RSpec.describe Gitlab::GlRepository::RepoType do
describe Gitlab::GlRepository::WIKI do describe Gitlab::GlRepository::WIKI do
context 'group wiki' do context 'group wiki' do
let_it_be(:group) { create(:group) } let_it_be(:wiki) { create(:group_wiki) }
it_behaves_like 'a repo type' do it_behaves_like 'a repo type' do
let(:expected_id) { group.id } let(:expected_id) { wiki.group.id }
let(:expected_identifier) { "group-#{expected_id}-wiki" } let(:expected_identifier) { "group-#{expected_id}-wiki" }
let(:expected_suffix) { '.wiki' } let(:expected_suffix) { '.wiki' }
let(:expected_container) { group } let(:expected_container) { wiki }
let(:expected_repository) { ::Repository.new(group.wiki.full_path, group, shard: group.wiki.repository_storage, disk_path: group.wiki.disk_path, repo_type: Gitlab::GlRepository::WIKI) } let(:expected_repository) { ::Repository.new(wiki.full_path, wiki, shard: wiki.repository_storage, disk_path: wiki.disk_path, repo_type: Gitlab::GlRepository::WIKI) }
end end
end end
end end
......
...@@ -8,7 +8,7 @@ RSpec.describe ::Gitlab::GlRepository do ...@@ -8,7 +8,7 @@ RSpec.describe ::Gitlab::GlRepository do
# Group Wiki is a GitLab Starter feature # Group Wiki is a GitLab Starter feature
it 'parses a group wiki gl_repository' do it 'parses a group wiki gl_repository' do
expect(described_class.parse("group-#{group.id}-wiki")).to eq([group, nil, Gitlab::GlRepository::WIKI]) expect(described_class.parse("group-#{group.id}-wiki")).to eq([group.wiki, nil, Gitlab::GlRepository::WIKI])
end end
end end
end end
...@@ -275,4 +275,16 @@ RSpec.describe Repository do ...@@ -275,4 +275,16 @@ RSpec.describe Repository do
end end
end end
end end
describe '#lfs_enabled?' do
subject { repository.lfs_enabled? }
context 'for a group wiki repository' do
let(:repository) { build_stubbed(:group_wiki).repository }
it 'returns false' do
is_expected.to be_falsy
end
end
end
end end
...@@ -221,7 +221,7 @@ RSpec.describe Geo::RepositoryVerificationPrimaryService do ...@@ -221,7 +221,7 @@ RSpec.describe Geo::RepositoryVerificationPrimaryService do
def stub_wiki_repository(wiki, repository) def stub_wiki_repository(wiki, repository)
allow(Repository).to receive(:new).with( allow(Repository).to receive(:new).with(
project.wiki.full_path, project.wiki.full_path,
project, project.wiki,
shard: project.repository_storage, shard: project.repository_storage,
disk_path: project.wiki.disk_path, disk_path: project.wiki.disk_path,
repo_type: Gitlab::GlRepository::WIKI repo_type: Gitlab::GlRepository::WIKI
......
...@@ -100,7 +100,7 @@ RSpec.describe PostReceive do ...@@ -100,7 +100,7 @@ RSpec.describe PostReceive do
describe '#process_wiki_changes' do describe '#process_wiki_changes' do
let(:wiki) { build(:project_wiki, project: project) } let(:wiki) { build(:project_wiki, project: project) }
let(:gl_repository) { wiki.repository.repo_type.identifier_for_container(wiki.container) } let(:gl_repository) { wiki.repository.repo_type.identifier_for_container(wiki) }
it 'calls Git::WikiPushService#execute' do it 'calls Git::WikiPushService#execute' do
expect_next_instance_of(::Git::WikiPushService) do |service| expect_next_instance_of(::Git::WikiPushService) do |service|
......
...@@ -44,11 +44,7 @@ module Gitlab ...@@ -44,11 +44,7 @@ module Gitlab
end end
def url_to_repo def url_to_repo
protocol == 'ssh' ? message_subject.ssh_url_to_repo : message_subject.http_url_to_repo protocol == 'ssh' ? container.ssh_url_to_repo : container.http_url_to_repo
end
def message_subject
repository.repo_type.wiki? ? project.wiki : container
end end
end end
end end
......
...@@ -137,6 +137,10 @@ module Gitlab ...@@ -137,6 +137,10 @@ module Gitlab
private private
def check_container! def check_container!
# Strict nil check, to avoid any surprises with Object#present?
# which can delegate to #empty?
raise NotFoundError, not_found_message if container.nil?
check_project! if project? check_project! if project?
end end
...@@ -204,9 +208,7 @@ module Gitlab ...@@ -204,9 +208,7 @@ module Gitlab
end end
def check_project_accessibility! def check_project_accessibility!
if project.blank? || !can_read_project? raise NotFoundError, not_found_message unless can_read_project?
raise NotFoundError, not_found_message
end
end end
def not_found_message def not_found_message
...@@ -279,10 +281,10 @@ module Gitlab ...@@ -279,10 +281,10 @@ module Gitlab
error_message(:download) error_message(:download)
end end
# We assume that all git-access classes are in project context by default.
# Override this method to be more specific.
def project? def project?
true # Strict nil check, to avoid any surprises with Object#present?
# which can delegate to #empty?
!project.nil?
end end
def project def project
...@@ -290,7 +292,7 @@ module Gitlab ...@@ -290,7 +292,7 @@ module Gitlab
end end
def check_push_access! def check_push_access!
if container.repository_read_only? if project&.repository_read_only?
raise ForbiddenError, error_message(:read_only) raise ForbiddenError, error_message(:read_only)
end end
......
...@@ -12,7 +12,7 @@ module Gitlab ...@@ -12,7 +12,7 @@ module Gitlab
# 'data' => { # 'data' => {
# 'api_endpoints' => %w{geo/proxy_git_ssh/info_refs_receive_pack geo/proxy_git_ssh/receive_pack}, # 'api_endpoints' => %w{geo/proxy_git_ssh/info_refs_receive_pack geo/proxy_git_ssh/receive_pack},
# 'gl_username' => user.username, # 'gl_username' => user.username,
# 'primary_repo' => geo_primary_http_url_to_repo(project_or_wiki) # 'primary_repo' => geo_primary_http_url_to_repo(container)
# } # }
# } # }
# #
......
...@@ -21,6 +21,11 @@ module Gitlab ...@@ -21,6 +21,11 @@ module Gitlab
@authentication_abilities &= [:download_code, :push_code] @authentication_abilities &= [:download_code, :push_code]
end end
override :project
def project
container.project if container.is_a?(ProjectSnippet)
end
override :check override :check
def check(cmd, changes) def check(cmd, changes)
check_snippet_accessibility! check_snippet_accessibility!
...@@ -46,16 +51,6 @@ module Gitlab ...@@ -46,16 +51,6 @@ module Gitlab
# snippets never return custom actions, such as geo replication. # snippets never return custom actions, such as geo replication.
end end
override :project?
def project?
project_snippet?
end
override :project
def project
snippet&.project
end
override :check_valid_actor! override :check_valid_actor!
def check_valid_actor! def check_valid_actor!
# TODO: Investigate if expanding actor/authentication types are needed. # TODO: Investigate if expanding actor/authentication types are needed.
...@@ -71,10 +66,6 @@ module Gitlab ...@@ -71,10 +66,6 @@ module Gitlab
actor.is_a?(User) || actor.instance_of?(Key) actor.is_a?(User) || actor.instance_of?(Key)
end end
def project_snippet?
snippet.is_a?(ProjectSnippet)
end
override :check_push_access! override :check_push_access!
def check_push_access! def check_push_access!
raise ForbiddenError, ERROR_MESSAGES[:update_snippet] unless user raise ForbiddenError, ERROR_MESSAGES[:update_snippet] unless user
......
...@@ -12,6 +12,11 @@ module Gitlab ...@@ -12,6 +12,11 @@ module Gitlab
write_to_wiki: "You are not allowed to write to this project's wiki." write_to_wiki: "You are not allowed to write to this project's wiki."
}.freeze }.freeze
override :project
def project
container.project if container.is_a?(ProjectWiki)
end
override :download_ability override :download_ability
def download_ability def download_ability
:download_wiki_code :download_wiki_code
...@@ -40,11 +45,6 @@ module Gitlab ...@@ -40,11 +45,6 @@ module Gitlab
def not_found_message def not_found_message
error_message(:not_found) error_message(:not_found)
end end
override :repository
def repository
container.wiki.repository
end
end end
end end
......
...@@ -4,6 +4,8 @@ module Gitlab ...@@ -4,6 +4,8 @@ module Gitlab
class GlRepository class GlRepository
include Singleton include Singleton
# TODO: Refactor these constants into proper classes
# https://gitlab.com/gitlab-org/gitlab/-/issues/259008
PROJECT = RepoType.new( PROJECT = RepoType.new(
name: :project, name: :project,
access_checker_class: Gitlab::GitAccessProject, access_checker_class: Gitlab::GitAccessProject,
...@@ -12,8 +14,12 @@ module Gitlab ...@@ -12,8 +14,12 @@ module Gitlab
WIKI = RepoType.new( WIKI = RepoType.new(
name: :wiki, name: :wiki,
access_checker_class: Gitlab::GitAccessWiki, access_checker_class: Gitlab::GitAccessWiki,
repository_resolver: -> (container) { ::Repository.new(container.wiki.full_path, container, shard: container.wiki.repository_storage, disk_path: container.wiki.disk_path, repo_type: WIKI) }, repository_resolver: -> (container) do
project_resolver: -> (container) { container.is_a?(Project) ? container : nil }, wiki = container.is_a?(Wiki) ? container : container.wiki # Also allow passing a Project, Group, or Geo::DeletedProject
::Repository.new(wiki.full_path, wiki, shard: wiki.repository_storage, disk_path: wiki.disk_path, repo_type: WIKI)
end,
container_class: ProjectWiki,
project_resolver: -> (wiki) { wiki.try(:project) },
suffix: :wiki suffix: :wiki
).freeze ).freeze
SNIPPET = RepoType.new( SNIPPET = RepoType.new(
......
...@@ -53,12 +53,13 @@ module Gitlab ...@@ -53,12 +53,13 @@ module Gitlab
private private
def container_class def container_class
case @container_type # NOTE: This is currently only used and supported for group wikis
when 'project' # https://gitlab.com/gitlab-org/gitlab/-/issues/219192
Project return unless @repo_type_name == 'wiki'
when 'group'
Group "#{@container_type}_#{@repo_type_name}".classify.constantize
end rescue NameError
nil
end end
end end
......
...@@ -29,10 +29,6 @@ module Gitlab ...@@ -29,10 +29,6 @@ module Gitlab
end end
def identifier_for_container(container) def identifier_for_container(container)
if container.is_a?(Group)
return "#{container.class.name.underscore}-#{container.id}-#{name}"
end
"#{name}-#{container.id}" "#{name}-#{container.id}"
end end
...@@ -84,3 +80,5 @@ module Gitlab ...@@ -84,3 +80,5 @@ module Gitlab
end end
end end
end end
Gitlab::GlRepository::RepoType.prepend_if_ee('EE::Gitlab::GlRepository::RepoType')
...@@ -35,6 +35,10 @@ module Gitlab ...@@ -35,6 +35,10 @@ module Gitlab
snippet, redirected_path = find_snippet(full_path) snippet, redirected_path = find_snippet(full_path)
[snippet, snippet&.project, redirected_path] [snippet, snippet&.project, redirected_path]
elsif type.wiki?
wiki, redirected_path = find_wiki(full_path)
[wiki, wiki.try(:project), redirected_path]
else else
project, redirected_path = find_project(full_path) project, redirected_path = find_project(full_path)
...@@ -67,6 +71,17 @@ module Gitlab ...@@ -67,6 +71,17 @@ module Gitlab
[Snippet.find_by_id_and_project(id: snippet_id, project: project), redirected_path] [Snippet.find_by_id_and_project(id: snippet_id, project: project), redirected_path]
end end
# Wiki path can be either:
# - namespace/project
# - group/subgroup/project
def self.find_wiki(wiki_path)
return [nil, nil] if wiki_path.blank?
project, redirected_path = find_project(wiki_path)
[project&.wiki, redirected_path]
end
def self.extract_snippet_info(snippet_path) def self.extract_snippet_info(snippet_path)
path_segments = snippet_path.split('/') path_segments = snippet_path.split('/')
snippet_id = path_segments.pop snippet_id = path_segments.pop
......
...@@ -54,14 +54,18 @@ RSpec.describe WikiHelper do ...@@ -54,14 +54,18 @@ RSpec.describe WikiHelper do
end end
describe '#wiki_attachment_upload_url' do describe '#wiki_attachment_upload_url' do
it 'returns the upload endpoint for project wikis' do let_it_be(:wiki) { build_stubbed(:project_wiki) }
@wiki = build_stubbed(:project_wiki)
before do
@wiki = wiki
end
it 'returns the upload endpoint for project wikis' do
expect(helper.wiki_attachment_upload_url).to end_with("/api/v4/projects/#{@wiki.project.id}/wikis/attachments") expect(helper.wiki_attachment_upload_url).to end_with("/api/v4/projects/#{@wiki.project.id}/wikis/attachments")
end end
it 'raises an exception for unsupported wiki containers' do it 'raises an exception for unsupported wiki containers' do
@wiki = Wiki.new(User.new) allow(wiki).to receive(:container).and_return(User.new)
expect do expect do
helper.wiki_attachment_upload_url helper.wiki_attachment_upload_url
......
...@@ -428,14 +428,12 @@ RSpec.describe Gitlab::GitAccess do ...@@ -428,14 +428,12 @@ RSpec.describe Gitlab::GitAccess do
end end
context 'when the project repository does not exist' do context 'when the project repository does not exist' do
it 'returns not found' do before do
project.add_guest(user) project.add_guest(user)
repo = project.repository allow(project.repository).to receive(:exists?).and_return(false)
Gitlab::GitalyClient::StorageSettings.allow_disk_access { FileUtils.rm_rf(repo.path) } end
# Sanity check for rm_rf
expect(repo.exists?).to eq(false)
it 'returns not found' do
expect { pull_access_check }.to raise_error(Gitlab::GitAccess::NotFoundError, 'A repository for this project does not exist yet.') expect { pull_access_check }.to raise_error(Gitlab::GitAccess::NotFoundError, 'A repository for this project does not exist yet.')
end end
end end
......
...@@ -3,17 +3,17 @@ ...@@ -3,17 +3,17 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::GitAccessWiki do RSpec.describe Gitlab::GitAccessWiki do
let(:access) { described_class.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
let_it_be(:project) { create(:project, :wiki_repo) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :wiki_repo) }
let_it_be(:wiki) { create(:project_wiki, project: project) }
let(:changes) { ['6f6d7e7ed 570e7b2ab refs/heads/master'] } let(:changes) { ['6f6d7e7ed 570e7b2ab refs/heads/master'] }
let(:authentication_abilities) { %i[read_project download_code push_code] }
let(:redirected_path) { nil } let(:redirected_path) { nil }
let(:authentication_abilities) do
[ let(:access) do
:read_project, described_class.new(user, wiki, 'web',
:download_code, authentication_abilities: authentication_abilities,
:push_code redirected_path: redirected_path)
]
end end
describe '#push_access_check' do describe '#push_access_check' do
...@@ -64,7 +64,7 @@ RSpec.describe Gitlab::GitAccessWiki do ...@@ -64,7 +64,7 @@ RSpec.describe Gitlab::GitAccessWiki do
context 'when the repository does not exist' do context 'when the repository does not exist' do
before do before do
allow(project.wiki).to receive(:repository).and_return(double('Repository', exists?: false)) allow(wiki.repository).to receive(:exists?).and_return(false)
end end
it_behaves_like 'not-found git access' do it_behaves_like 'not-found git access' do
......
...@@ -35,14 +35,14 @@ RSpec.describe Gitlab::GlRepository::Identifier do ...@@ -35,14 +35,14 @@ RSpec.describe Gitlab::GlRepository::Identifier do
it_behaves_like 'parsing gl_repository identifier' do it_behaves_like 'parsing gl_repository identifier' do
let(:record_id) { project.id } let(:record_id) { project.id }
let(:identifier) { "wiki-#{record_id}" } let(:identifier) { "wiki-#{record_id}" }
let(:expected_container) { project } let(:expected_container) { project.wiki }
let(:expected_type) { Gitlab::GlRepository::WIKI } let(:expected_type) { Gitlab::GlRepository::WIKI }
end end
it_behaves_like 'parsing gl_repository identifier' do it_behaves_like 'parsing gl_repository identifier' do
let(:record_id) { project.id } let(:record_id) { project.id }
let(:identifier) { "project-#{record_id}-wiki" } let(:identifier) { "project-#{record_id}-wiki" }
let(:expected_container) { project } let(:expected_container) { project.wiki }
let(:expected_type) { Gitlab::GlRepository::WIKI } let(:expected_type) { Gitlab::GlRepository::WIKI }
end end
end end
...@@ -87,7 +87,8 @@ RSpec.describe Gitlab::GlRepository::Identifier do ...@@ -87,7 +87,8 @@ RSpec.describe Gitlab::GlRepository::Identifier do
'project-wibble-wiki', 'project-wibble-wiki',
'wiki-1-project', 'wiki-1-project',
'snippet', 'snippet',
'project-1-wiki-bar' 'project-1-wiki-bar',
'project-1-project'
] ]
end end
...@@ -96,10 +97,5 @@ RSpec.describe Gitlab::GlRepository::Identifier do ...@@ -96,10 +97,5 @@ RSpec.describe Gitlab::GlRepository::Identifier do
expect { described_class.parse(identifier) }.to raise_error(described_class::InvalidIdentifier) expect { described_class.parse(identifier) }.to raise_error(described_class::InvalidIdentifier)
end end
end end
it 'raises InvalidIdentifier on project-1-project' do
pending 'https://gitlab.com/gitlab-org/gitlab/-/issues/219192'
expect { described_class.parse('project-1-project') }.to raise_error(described_class::InvalidIdentifier)
end
end end
end end
...@@ -41,12 +41,14 @@ RSpec.describe Gitlab::GlRepository::RepoType do ...@@ -41,12 +41,14 @@ RSpec.describe Gitlab::GlRepository::RepoType do
end end
describe Gitlab::GlRepository::WIKI do describe Gitlab::GlRepository::WIKI do
let(:wiki) { project.wiki }
it_behaves_like 'a repo type' do it_behaves_like 'a repo type' do
let(:expected_id) { project.id } let(:expected_id) { wiki.project.id }
let(:expected_identifier) { "wiki-#{expected_id}" } let(:expected_identifier) { "wiki-#{expected_id}" }
let(:expected_suffix) { '.wiki' } let(:expected_suffix) { '.wiki' }
let(:expected_container) { project } let(:expected_container) { wiki }
let(:expected_repository) { ::Repository.new(project.wiki.full_path, project, shard: project.wiki.repository_storage, disk_path: project.wiki.disk_path, repo_type: Gitlab::GlRepository::WIKI) } let(:expected_repository) { ::Repository.new(wiki.full_path, wiki, shard: wiki.repository_storage, disk_path: wiki.disk_path, repo_type: Gitlab::GlRepository::WIKI) }
end end
it 'knows its type' do it 'knows its type' do
......
...@@ -12,7 +12,7 @@ RSpec.describe ::Gitlab::GlRepository do ...@@ -12,7 +12,7 @@ RSpec.describe ::Gitlab::GlRepository do
end end
it 'parses a project wiki gl_repository' do it 'parses a project wiki gl_repository' do
expect(described_class.parse("wiki-#{project.id}")).to eq([project, project, Gitlab::GlRepository::WIKI]) expect(described_class.parse("wiki-#{project.id}")).to eq([project.wiki, project, Gitlab::GlRepository::WIKI])
end end
it 'parses a snippet gl_repository' do it 'parses a snippet gl_repository' do
......
...@@ -18,7 +18,7 @@ RSpec.describe ::Gitlab::RepoPath do ...@@ -18,7 +18,7 @@ RSpec.describe ::Gitlab::RepoPath do
end end
it 'parses a full wiki project path' do it 'parses a full wiki project path' do
expect(described_class.parse(project.wiki.repository.full_path)).to eq([project, project, Gitlab::GlRepository::WIKI, nil]) expect(described_class.parse(project.wiki.repository.full_path)).to eq([project.wiki, project, Gitlab::GlRepository::WIKI, nil])
end end
it 'parses a personal snippet repository path' do it 'parses a personal snippet repository path' do
...@@ -36,7 +36,7 @@ RSpec.describe ::Gitlab::RepoPath do ...@@ -36,7 +36,7 @@ RSpec.describe ::Gitlab::RepoPath do
end end
it 'parses a relative wiki path' do it 'parses a relative wiki path' do
expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project, project, Gitlab::GlRepository::WIKI, nil]) expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project.wiki, project, Gitlab::GlRepository::WIKI, nil])
end end
it 'parses a relative path starting with /' do it 'parses a relative path starting with /' do
...@@ -49,7 +49,7 @@ RSpec.describe ::Gitlab::RepoPath do ...@@ -49,7 +49,7 @@ RSpec.describe ::Gitlab::RepoPath do
end end
it 'parses a relative wiki path' do it 'parses a relative wiki path' do
expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project, project, Gitlab::GlRepository::WIKI, redirect_route]) expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project.wiki, project, Gitlab::GlRepository::WIKI, redirect_route])
end end
it 'parses a relative path starting with /' do it 'parses a relative path starting with /' do
......
...@@ -136,6 +136,7 @@ RSpec.describe Project do ...@@ -136,6 +136,7 @@ RSpec.describe Project do
let_it_be(:container) { create(:project, :repository, path: 'somewhere') } let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
let(:stubbed_container) { build_stubbed(:project) } let(:stubbed_container) { build_stubbed(:project) }
let(:expected_full_path) { "#{container.namespace.full_path}/somewhere" } let(:expected_full_path) { "#{container.namespace.full_path}/somewhere" }
let(:expected_lfs_enabled) { true }
end end
it_behaves_like 'model with wiki' do it_behaves_like 'model with wiki' do
...@@ -4332,7 +4333,7 @@ RSpec.describe Project do ...@@ -4332,7 +4333,7 @@ RSpec.describe Project do
end end
it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the wiki repo is in use' do it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the wiki repo is in use' do
Gitlab::ReferenceCounter.new(Gitlab::GlRepository::WIKI.identifier_for_container(project)).increase Gitlab::ReferenceCounter.new(Gitlab::GlRepository::WIKI.identifier_for_container(project.wiki)).increase
expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in) expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in)
......
...@@ -6,6 +6,7 @@ RSpec.describe ProjectWiki do ...@@ -6,6 +6,7 @@ RSpec.describe ProjectWiki do
it_behaves_like 'wiki model' do it_behaves_like 'wiki model' do
let(:wiki_container) { create(:project, :wiki_repo, namespace: user.namespace) } let(:wiki_container) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:wiki_container_without_repo) { create(:project, namespace: user.namespace) } let(:wiki_container_without_repo) { create(:project, namespace: user.namespace) }
let(:wiki_lfs_enabled) { true }
it { is_expected.to delegate_method(:storage).to(:container) } 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(:repository_storage).to(:container) }
......
...@@ -2688,7 +2688,7 @@ RSpec.describe Repository do ...@@ -2688,7 +2688,7 @@ RSpec.describe Repository do
expect(subject).to be_a(Gitlab::Git::Repository) expect(subject).to be_a(Gitlab::Git::Repository)
expect(subject.relative_path).to eq(project.disk_path + '.wiki.git') expect(subject.relative_path).to eq(project.disk_path + '.wiki.git')
expect(subject.gl_repository).to eq("wiki-#{project.id}") expect(subject.gl_repository).to eq("wiki-#{project.id}")
expect(subject.gl_project_path).to eq(project.full_path) expect(subject.gl_project_path).to eq(project.wiki.full_path)
end end
end end
end end
...@@ -2941,12 +2941,19 @@ RSpec.describe Repository do ...@@ -2941,12 +2941,19 @@ RSpec.describe Repository do
expect(snippet.repository.project).to be_nil expect(snippet.repository.project).to be_nil
end end
it 'returns the project for a project wiki' do
wiki = create(:project_wiki)
expect(wiki.project).to be(wiki.repository.project)
end
it 'returns the container if it is a project' do it 'returns the container if it is a project' do
expect(repository.project).to be(project) expect(repository.project).to be(project)
end end
it 'returns nil if the container is not a project' do it 'returns nil if the container is not a project' do
expect(repository).to receive(:container).and_return(Group.new) repository.container = Group.new
expect(repository.project).to be_nil expect(repository.project).to be_nil
end end
end end
...@@ -2981,17 +2988,11 @@ RSpec.describe Repository do ...@@ -2981,17 +2988,11 @@ RSpec.describe Repository do
context 'for a project wiki repository' do context 'for a project wiki repository' do
let(:repository) { project.wiki.repository } let(:repository) { project.wiki.repository }
it 'returns true when LFS is enabled' do it 'delegates to the project' do
stub_lfs_setting(enabled: true) expect(project).to receive(:lfs_enabled?).and_return(true)
is_expected.to be_truthy is_expected.to be_truthy
end end
it 'returns false when LFS is disabled' do
stub_lfs_setting(enabled: false)
is_expected.to be_falsy
end
end end
context 'for a project snippet repository' do context 'for a project snippet repository' do
......
# frozen_string_literal: true
require "spec_helper"
RSpec.describe Wiki do
describe '.new' do
it 'verifies that the user is a User' do
expect { described_class.new(double, 1) }.to raise_error(ArgumentError)
expect { described_class.new(double, build(:group)) }.to raise_error(ArgumentError)
expect { described_class.new(double, build(:user)) }.not_to raise_error
expect { described_class.new(double, nil) }.not_to raise_error
end
end
end
...@@ -461,7 +461,7 @@ RSpec.describe API::Internal::Base do ...@@ -461,7 +461,7 @@ RSpec.describe API::Internal::Base do
end end
it_behaves_like 'sets hook env' do it_behaves_like 'sets hook env' do
let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_container(project) } let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_container(project.wiki) }
end end
end end
......
...@@ -9,7 +9,7 @@ RSpec.describe Repositories::DestroyService do ...@@ -9,7 +9,7 @@ RSpec.describe Repositories::DestroyService do
let(:path) { repository.disk_path } let(:path) { repository.disk_path }
let(:remove_path) { "#{path}+#{project.id}#{described_class::DELETED_FLAG}" } let(:remove_path) { "#{path}+#{project.id}#{described_class::DELETED_FLAG}" }
subject { described_class.new(project.repository).execute } subject { described_class.new(repository).execute }
it 'moves the repository to a +deleted folder' do it 'moves the repository to a +deleted folder' do
expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_truthy expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_truthy
...@@ -92,4 +92,22 @@ RSpec.describe Repositories::DestroyService do ...@@ -92,4 +92,22 @@ RSpec.describe Repositories::DestroyService do
service.execute service.execute
end end
end end
context 'with a project wiki repository' do
let(:project) { create(:project, :wiki_repo) }
let(:repository) { project.wiki.repository }
it 'schedules the repository deletion' do
subject
expect(Repositories::ShellDestroyService).to receive(:new).with(repository).and_call_original
expect(GitlabShellWorker).to receive(:perform_in)
.with(Repositories::ShellDestroyService::REPO_REMOVAL_DELAY, :remove_repository, project.repository_storage, remove_path)
# Because GitlabShellWorker is inside a run_after_commit callback we need to
# trigger the callback
project.touch
end
end
end end
...@@ -4,7 +4,7 @@ module APIInternalBaseHelpers ...@@ -4,7 +4,7 @@ module APIInternalBaseHelpers
def gl_repository_for(container) def gl_repository_for(container)
case container case container
when ProjectWiki when ProjectWiki
Gitlab::GlRepository::WIKI.identifier_for_container(container.project) Gitlab::GlRepository::WIKI.identifier_for_container(container)
when Project when Project
Gitlab::GlRepository::PROJECT.identifier_for_container(container) Gitlab::GlRepository::PROJECT.identifier_for_container(container)
when Snippet when Snippet
......
...@@ -6,6 +6,14 @@ RSpec.shared_examples 'model with repository' do ...@@ -6,6 +6,14 @@ RSpec.shared_examples 'model with repository' do
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 } let(:expected_repo_url_path) { expected_full_path }
let(:expected_lfs_enabled) { false }
it 'container class includes HasRepository' do
# NOTE: This is not enforced at runtime, since we also need to support Geo::DeletedProject
expect(described_class).to include_module(HasRepository)
expect(container).to be_kind_of(HasRepository)
expect(stubbed_container).to be_kind_of(HasRepository)
end
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 }
...@@ -74,6 +82,10 @@ RSpec.shared_examples 'model with repository' do ...@@ -74,6 +82,10 @@ RSpec.shared_examples 'model with repository' do
it 'returns valid repo' do it 'returns valid repo' do
expect(container.repository).to be_kind_of(Repository) expect(container.repository).to be_kind_of(Repository)
end end
it 'uses the same container' do
expect(container.repository.container).to be(container)
end
end end
describe '#storage' do describe '#storage' do
...@@ -88,6 +100,16 @@ RSpec.shared_examples 'model with repository' do ...@@ -88,6 +100,16 @@ RSpec.shared_examples 'model with repository' do
end end
end end
describe '#lfs_enabled?' do
before do
stub_lfs_setting(enabled: true)
end
it 'returns the expected value' do
expect(container.lfs_enabled?).to eq(expected_lfs_enabled)
end
end
describe '#empty_repo?' do describe '#empty_repo?' do
context 'when the repo does not exist' do context 'when the repo does not exist' do
it 'returns true' do it 'returns true' do
......
...@@ -4,21 +4,99 @@ RSpec.shared_examples 'wiki model' do ...@@ -4,21 +4,99 @@ RSpec.shared_examples 'wiki model' do
let_it_be(:user) { create(:user, :commit_email) } let_it_be(:user) { create(:user, :commit_email) }
let(:wiki_container) { raise NotImplementedError } let(:wiki_container) { raise NotImplementedError }
let(:wiki_container_without_repo) { raise NotImplementedError } let(:wiki_container_without_repo) { raise NotImplementedError }
let(:wiki_lfs_enabled) { false }
let(:wiki) { described_class.new(wiki_container, user) } let(:wiki) { described_class.new(wiki_container, user) }
let(:commit) { subject.repository.head_commit } let(:commit) { subject.repository.head_commit }
subject { wiki } subject { wiki }
it 'container class includes HasWiki' do
# NOTE: This is not enforced at runtime, since we also need to support Geo::DeletedProject
expect(wiki_container).to be_kind_of(HasWiki)
expect(wiki_container_without_repo).to be_kind_of(HasWiki)
end
it_behaves_like 'model with repository' do it_behaves_like 'model with repository' do
let(:container) { wiki } let(:container) { wiki }
let(:stubbed_container) { described_class.new(wiki_container_without_repo, user) } let(:stubbed_container) { described_class.new(wiki_container_without_repo, user) }
let(:expected_full_path) { "#{container.container.full_path}.wiki" } 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" } let(:expected_web_url_path) { "#{container.container.web_url(only_path: true).sub(%r{^/}, '')}/-/wikis/home" }
let(:expected_lfs_enabled) { wiki_lfs_enabled }
end
describe '.container_class' do
it 'is set to the container class' do
expect(described_class.container_class).to eq(wiki_container.class)
end
end
describe '.find_by_id' do
it 'returns a wiki instance if the container is found' do
wiki = described_class.find_by_id(wiki_container.id)
expect(wiki).to be_a(described_class)
expect(wiki.container).to eq(wiki_container)
end
it 'returns nil if the container is not found' do
expect(described_class.find_by_id(-1)).to be_nil
end
end
describe '#initialize' do
it 'accepts a valid user' do
expect do
described_class.new(wiki_container, user)
end.not_to raise_error
end
it 'accepts a blank user' do
expect do
described_class.new(wiki_container, nil)
end.not_to raise_error
end
it 'raises an error for invalid users' do
expect do
described_class.new(wiki_container, Object.new)
end.to raise_error(ArgumentError, 'user must be a User, got Object')
end
end
describe '#run_after_commit' do
it 'delegates to the container' do
expect(wiki_container).to receive(:run_after_commit)
wiki.run_after_commit
end
end
describe '#==' do
it 'returns true for wikis from the same container' do
expect(wiki).to eq(described_class.new(wiki_container))
end
it 'returns false for wikis from different containers' do
expect(wiki).not_to eq(described_class.new(wiki_container_without_repo))
end
end
describe '#id' do
it 'returns the ID of the container' do
expect(wiki.id).to eq(wiki_container.id)
end
end
describe '#to_global_id' do
it 'returns a global ID' do
expect(wiki.to_global_id.to_s).to eq("gid://gitlab/#{wiki.class.name}/#{wiki.id}")
end
end end
describe '#repository' do describe '#repository' do
it 'returns a wiki repository' do it 'returns a wiki repository' do
expect(subject.repository.repo_type).to be_wiki expect(subject.repository.repo_type).to be_wiki
expect(subject.repository.container).to be(subject)
end end
end end
......
...@@ -281,7 +281,7 @@ RSpec.describe PostReceive do ...@@ -281,7 +281,7 @@ RSpec.describe PostReceive do
before do before do
# Need to mock here so we can expect calls on project # Need to mock here so we can expect calls on project
allow(Gitlab::GlRepository).to receive(:parse).and_return([project, project, Gitlab::GlRepository::WIKI]) allow(Gitlab::GlRepository).to receive(:parse).and_return([project.wiki, project, Gitlab::GlRepository::WIKI])
end end
it 'updates project activity' do it 'updates project activity' do
......
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