Commit 2f7c980d authored by Imre Farkas's avatar Imre Farkas

Add setting to disable project forking

It also adds a new ProjectSetting table to store this setting and can be
used in the future as the Project table already has too many columns.
parent 9cd82c24
...@@ -104,6 +104,7 @@ export default { ...@@ -104,6 +104,7 @@ export default {
visibilityLevel: visibilityOptions.PUBLIC, visibilityLevel: visibilityOptions.PUBLIC,
issuesAccessLevel: 20, issuesAccessLevel: 20,
repositoryAccessLevel: 20, repositoryAccessLevel: 20,
forkingEnabled: true,
mergeRequestsAccessLevel: 20, mergeRequestsAccessLevel: 20,
buildsAccessLevel: 20, buildsAccessLevel: 20,
wikiAccessLevel: 20, wikiAccessLevel: 20,
...@@ -300,6 +301,18 @@ export default { ...@@ -300,6 +301,18 @@ export default {
name="project[project_feature_attributes][merge_requests_access_level]" name="project[project_feature_attributes][merge_requests_access_level]"
/> />
</project-setting-row> </project-setting-row>
<project-setting-row
:label="s__('ProjectSettings|Forks')"
:help-text="
s__('ProjectSettings|Allow users to make copies of your repository to a new project')
"
>
<project-feature-toggle
v-model="forkingEnabled"
:disabled-input="!repositoryEnabled"
name="project[project_setting_attributes][forking_enabled]"
/>
</project-setting-row>
<project-setting-row <project-setting-row
:label="s__('ProjectSettings|Pipelines')" :label="s__('ProjectSettings|Pipelines')"
:help-text="s__('ProjectSettings|Build, test, and deploy your changes')" :help-text="s__('ProjectSettings|Build, test, and deploy your changes')"
......
...@@ -12,11 +12,13 @@ export default { ...@@ -12,11 +12,13 @@ export default {
this.buildsAccessLevel = Math.min(this.buildsAccessLevel, value); this.buildsAccessLevel = Math.min(this.buildsAccessLevel, value);
if (value === 0) { if (value === 0) {
this.forkingEnabled = false;
this.containerRegistryEnabled = false; this.containerRegistryEnabled = false;
this.lfsEnabled = false; this.lfsEnabled = false;
} }
} else if (oldValue === 0) { } else if (oldValue === 0) {
this.mergeRequestsAccessLevel = value; this.mergeRequestsAccessLevel = value;
this.forkingEnabled = true;
this.buildsAccessLevel = value; this.buildsAccessLevel = value;
this.containerRegistryEnabled = true; this.containerRegistryEnabled = true;
this.lfsEnabled = true; this.lfsEnabled = true;
......
...@@ -9,6 +9,7 @@ class Projects::ForksController < Projects::ApplicationController ...@@ -9,6 +9,7 @@ class Projects::ForksController < Projects::ApplicationController
before_action :require_non_empty_project before_action :require_non_empty_project
before_action :authorize_download_code! before_action :authorize_download_code!
before_action :authenticate_user!, only: [:new, :create] before_action :authenticate_user!, only: [:new, :create]
before_action :check_forking_availability, only: [:new, :create]
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def index def index
...@@ -61,7 +62,13 @@ class Projects::ForksController < Projects::ApplicationController ...@@ -61,7 +62,13 @@ class Projects::ForksController < Projects::ApplicationController
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
private
def whitelist_query_limiting def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42335') Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42335')
end end
def check_forking_availability
access_denied!(_('Forking is disabled for this project.')) unless @project.forking_enabled
end
end end
...@@ -396,6 +396,10 @@ class ProjectsController < Projects::ApplicationController ...@@ -396,6 +396,10 @@ class ProjectsController < Projects::ApplicationController
snippets_access_level snippets_access_level
wiki_access_level wiki_access_level
pages_access_level pages_access_level
],
project_setting_attributes: %i[
forking_enabled
] ]
] ]
end end
......
...@@ -563,6 +563,7 @@ module ProjectsHelper ...@@ -563,6 +563,7 @@ module ProjectsHelper
requestAccessEnabled: !!project.request_access_enabled, requestAccessEnabled: !!project.request_access_enabled,
issuesAccessLevel: feature.issues_access_level, issuesAccessLevel: feature.issues_access_level,
repositoryAccessLevel: feature.repository_access_level, repositoryAccessLevel: feature.repository_access_level,
forkingEnabled: project.forking_enabled,
mergeRequestsAccessLevel: feature.merge_requests_access_level, mergeRequestsAccessLevel: feature.merge_requests_access_level,
buildsAccessLevel: feature.builds_access_level, buildsAccessLevel: feature.builds_access_level,
wikiAccessLevel: feature.wiki_access_level, wikiAccessLevel: feature.wiki_access_level,
......
...@@ -235,6 +235,7 @@ class Project < ApplicationRecord ...@@ -235,6 +235,7 @@ class Project < ApplicationRecord
has_one :import_data, class_name: 'ProjectImportData', inverse_of: :project, autosave: true has_one :import_data, class_name: 'ProjectImportData', inverse_of: :project, autosave: true
has_one :project_feature, inverse_of: :project has_one :project_feature, inverse_of: :project
has_one :project_setting
has_one :statistics, class_name: 'ProjectStatistics' has_one :statistics, class_name: 'ProjectStatistics'
has_one :cluster_project, class_name: 'Clusters::Project' has_one :cluster_project, class_name: 'Clusters::Project'
...@@ -304,6 +305,7 @@ class Project < ApplicationRecord ...@@ -304,6 +305,7 @@ class Project < ApplicationRecord
accepts_nested_attributes_for :variables, allow_destroy: true accepts_nested_attributes_for :variables, allow_destroy: true
accepts_nested_attributes_for :project_feature, update_only: true accepts_nested_attributes_for :project_feature, update_only: true
accepts_nested_attributes_for :project_setting, update_only: true
accepts_nested_attributes_for :import_data accepts_nested_attributes_for :import_data
accepts_nested_attributes_for :auto_devops, update_only: true accepts_nested_attributes_for :auto_devops, update_only: true
accepts_nested_attributes_for :ci_cd_settings, update_only: true accepts_nested_attributes_for :ci_cd_settings, update_only: true
...@@ -334,6 +336,7 @@ class Project < ApplicationRecord ...@@ -334,6 +336,7 @@ class Project < ApplicationRecord
delegate :group_runners_enabled, :group_runners_enabled=, :group_runners_enabled?, to: :ci_cd_settings delegate :group_runners_enabled, :group_runners_enabled=, :group_runners_enabled?, to: :ci_cd_settings
delegate :root_ancestor, to: :namespace, allow_nil: true delegate :root_ancestor, to: :namespace, allow_nil: true
delegate :last_pipeline, to: :commit, allow_nil: true delegate :last_pipeline, to: :commit, allow_nil: true
delegate :forking_enabled, to: :project_setting, allow_nil: true
delegate :external_dashboard_url, to: :metrics_setting, allow_nil: true, prefix: true delegate :external_dashboard_url, to: :metrics_setting, allow_nil: true, prefix: true
delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci
...@@ -664,6 +667,10 @@ class Project < ApplicationRecord ...@@ -664,6 +667,10 @@ class Project < ApplicationRecord
super super
end end
def project_setting
super || build_project_setting
end
def all_pipelines def all_pipelines
if builds_enabled? if builds_enabled?
super super
......
# frozen_string_literal: true
class ProjectSetting < ApplicationRecord
self.primary_key = :project_id
belongs_to :project
validates :forking_enabled, inclusion: { in: [true, false] }
end
...@@ -83,6 +83,9 @@ class ProjectPolicy < BasePolicy ...@@ -83,6 +83,9 @@ class ProjectPolicy < BasePolicy
project.merge_requests_allowing_push_to_user(user).any? project.merge_requests_allowing_push_to_user(user).any?
end end
desc "Project allows forking"
condition(:forking_allowed) { @subject.forking_enabled }
with_scope :global with_scope :global
condition(:mirror_available, score: 0) do condition(:mirror_available, score: 0) do
::Gitlab::CurrentSettings.current_application_settings.mirror_available ::Gitlab::CurrentSettings.current_application_settings.mirror_available
...@@ -203,7 +206,6 @@ class ProjectPolicy < BasePolicy ...@@ -203,7 +206,6 @@ class ProjectPolicy < BasePolicy
enable :download_code enable :download_code
enable :read_statistics enable :read_statistics
enable :download_wiki_code enable :download_wiki_code
enable :fork_project
enable :create_project_snippet enable :create_project_snippet
enable :update_issue enable :update_issue
enable :reopen_issue enable :reopen_issue
...@@ -232,12 +234,15 @@ class ProjectPolicy < BasePolicy ...@@ -232,12 +234,15 @@ class ProjectPolicy < BasePolicy
enable :public_access enable :public_access
enable :guest_access enable :guest_access
enable :fork_project
enable :build_download_code enable :build_download_code
enable :build_read_container_image enable :build_read_container_image
enable :request_access enable :request_access
end end
rule { (can?(:public_user_access) | can?(:reporter_access)) & forking_allowed }.policy do
enable :fork_project
end
rule { owner | admin | guest | group_member }.prevent :request_access rule { owner | admin | guest | group_member }.prevent :request_access
rule { ~request_access_enabled }.prevent :request_access rule { ~request_access_enabled }.prevent :request_access
......
---
title: Add an option to configure forking restriction
merge_request: 17988
author:
type: added
# frozen_string_literal: true
class CreateProjectSettings < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
create_table(:project_settings, id: false) do |t|
t.references :project,
primary_key: true,
null: false,
index: { unique: true },
foreign_key: { on_delete: :cascade }
t.boolean :forking_enabled,
default: true,
null: false
t.datetime_with_timezone :updated_at, null: false
end
end
end
...@@ -3253,6 +3253,12 @@ ActiveRecord::Schema.define(version: 2020_01_14_204949) do ...@@ -3253,6 +3253,12 @@ ActiveRecord::Schema.define(version: 2020_01_14_204949) do
t.index ["project_id"], name: "index_project_repository_states_on_project_id", unique: true t.index ["project_id"], name: "index_project_repository_states_on_project_id", unique: true
end end
create_table "project_settings", primary_key: "project_id", id: :serial, force: :cascade do |t|
t.boolean "forking_enabled", default: true, null: false
t.datetime_with_timezone "updated_at", null: false
t.index ["project_id"], name: "index_project_settings_on_project_id", unique: true
end
create_table "project_statistics", id: :serial, force: :cascade do |t| create_table "project_statistics", id: :serial, force: :cascade do |t|
t.integer "project_id", null: false t.integer "project_id", null: false
t.integer "namespace_id", null: false t.integer "namespace_id", null: false
...@@ -4776,6 +4782,7 @@ ActiveRecord::Schema.define(version: 2020_01_14_204949) do ...@@ -4776,6 +4782,7 @@ ActiveRecord::Schema.define(version: 2020_01_14_204949) do
add_foreign_key "project_repositories", "projects", on_delete: :cascade add_foreign_key "project_repositories", "projects", on_delete: :cascade
add_foreign_key "project_repositories", "shards", on_delete: :restrict add_foreign_key "project_repositories", "shards", on_delete: :restrict
add_foreign_key "project_repository_states", "projects", on_delete: :cascade add_foreign_key "project_repository_states", "projects", on_delete: :cascade
add_foreign_key "project_settings", "projects", on_delete: :cascade
add_foreign_key "project_statistics", "projects", on_delete: :cascade add_foreign_key "project_statistics", "projects", on_delete: :cascade
add_foreign_key "project_tracing_settings", "projects", on_delete: :cascade add_foreign_key "project_tracing_settings", "projects", on_delete: :cascade
add_foreign_key "projects", "pool_repositories", name: "fk_6e5c14658a", on_delete: :nullify add_foreign_key "projects", "pool_repositories", name: "fk_6e5c14658a", on_delete: :nullify
......
...@@ -90,6 +90,7 @@ tree: ...@@ -90,6 +90,7 @@ tree:
- protected_tags: - protected_tags:
- :create_access_levels - :create_access_levels
- :project_feature - :project_feature
- :project_setting
- :custom_attributes - :custom_attributes
- :prometheus_metrics - :prometheus_metrics
- :project_badges - :project_badges
......
...@@ -8285,6 +8285,9 @@ msgstr "" ...@@ -8285,6 +8285,9 @@ msgstr ""
msgid "Forking in progress" msgid "Forking in progress"
msgstr "" msgstr ""
msgid "Forking is disabled for this project."
msgstr ""
msgid "Forking repository" msgid "Forking repository"
msgstr "" msgstr ""
...@@ -14346,6 +14349,9 @@ msgstr "" ...@@ -14346,6 +14349,9 @@ msgstr ""
msgid "ProjectSettings|All discussions must be resolved" msgid "ProjectSettings|All discussions must be resolved"
msgstr "" msgstr ""
msgid "ProjectSettings|Allow users to make copies of your repository to a new project"
msgstr ""
msgid "ProjectSettings|Allow users to request access" msgid "ProjectSettings|Allow users to request access"
msgstr "" msgstr ""
...@@ -14406,6 +14412,9 @@ msgstr "" ...@@ -14406,6 +14412,9 @@ msgstr ""
msgid "ProjectSettings|Fast-forward merges only" msgid "ProjectSettings|Fast-forward merges only"
msgstr "" msgstr ""
msgid "ProjectSettings|Forks"
msgstr ""
msgid "ProjectSettings|Git Large File Storage" msgid "ProjectSettings|Git Large File Storage"
msgstr "" msgstr ""
......
...@@ -12,6 +12,22 @@ describe Projects::ForksController do ...@@ -12,6 +12,22 @@ describe Projects::ForksController do
group.add_owner(user) group.add_owner(user)
end end
shared_examples 'forking disabled' do
let(:project) { create(:project, :private, :repository) }
before do
create(:project_setting, { project: project, forking_enabled: false })
project.add_developer(user)
sign_in(user)
end
it 'returns with 403' do
subject
expect(response).to have_gitlab_http_status(403)
end
end
describe 'GET index' do describe 'GET index' do
def get_forks(search: nil) def get_forks(search: nil)
get :index, get :index,
...@@ -138,19 +154,19 @@ describe Projects::ForksController do ...@@ -138,19 +154,19 @@ describe Projects::ForksController do
end end
describe 'GET new' do describe 'GET new' do
def get_new subject do
get :new, get :new,
params: { params: {
namespace_id: project.namespace, namespace_id: project.namespace,
project_id: project project_id: project
} }
end end
context 'when user is signed in' do context 'when user is signed in' do
it 'responds with status 200' do it 'responds with status 200' do
sign_in(user) sign_in(user)
get_new subject
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
end end
...@@ -160,21 +176,26 @@ describe Projects::ForksController do ...@@ -160,21 +176,26 @@ describe Projects::ForksController do
it 'redirects to the sign-in page' do it 'redirects to the sign-in page' do
sign_out(user) sign_out(user)
get_new subject
expect(response).to redirect_to(new_user_session_path) expect(response).to redirect_to(new_user_session_path)
end end
end end
it_behaves_like 'forking disabled'
end end
describe 'POST create' do describe 'POST create' do
def post_create(params = {}) let(:params) do
post :create, {
params: {
namespace_id: project.namespace, namespace_id: project.namespace,
project_id: project, project_id: project,
namespace_key: user.namespace.id namespace_key: user.namespace.id
}.merge(params) }
end
subject do
post :create, params: params
end end
context 'when user is signed in' do context 'when user is signed in' do
...@@ -183,18 +204,34 @@ describe Projects::ForksController do ...@@ -183,18 +204,34 @@ describe Projects::ForksController do
end end
it 'responds with status 302' do it 'responds with status 302' do
post_create subject
expect(response).to have_gitlab_http_status(302) expect(response).to have_gitlab_http_status(302)
expect(response).to redirect_to(namespace_project_import_path(user.namespace, project)) expect(response).to redirect_to(namespace_project_import_path(user.namespace, project))
end end
it 'passes continue params to the redirect' do context 'continue params' do
continue_params = { to: '/-/ide/project/path', notice: 'message' } let(:params) do
post_create continue: continue_params {
namespace_id: project.namespace,
project_id: project,
namespace_key: user.namespace.id,
continue: continue_params
}
end
let(:continue_params) do
{
to: '/-/ide/project/path',
notice: 'message'
}
end
it 'passes continue params to the redirect' do
subject
expect(response).to have_gitlab_http_status(302) expect(response).to have_gitlab_http_status(302)
expect(response).to redirect_to(namespace_project_import_path(user.namespace, project, continue: continue_params)) expect(response).to redirect_to(namespace_project_import_path(user.namespace, project, continue: continue_params))
end
end end
end end
...@@ -202,10 +239,12 @@ describe Projects::ForksController do ...@@ -202,10 +239,12 @@ describe Projects::ForksController do
it 'redirects to the sign-in page' do it 'redirects to the sign-in page' do
sign_out(user) sign_out(user)
post_create subject
expect(response).to redirect_to(new_user_session_path) expect(response).to redirect_to(new_user_session_path)
end end
end end
it_behaves_like 'forking disabled'
end end
end end
# frozen_string_literal: true
FactoryBot.define do
factory :project_setting do
project
end
end
...@@ -186,7 +186,7 @@ describe 'Edit Project Settings' do ...@@ -186,7 +186,7 @@ describe 'Edit Project Settings' do
click_button "Save changes" click_button "Save changes"
end end
expect(find(".sharing-permissions")).to have_selector(".project-feature-toggle.is-disabled", count: 2) expect(find(".sharing-permissions")).to have_selector(".project-feature-toggle.is-disabled", count: 3)
end end
it "shows empty features project homepage" do it "shows empty features project homepage" do
......
...@@ -27,6 +27,53 @@ describe 'Project fork' do ...@@ -27,6 +27,53 @@ describe 'Project fork' do
expect(page).to have_css('a.disabled', text: 'Fork') expect(page).to have_css('a.disabled', text: 'Fork')
end end
context 'forking enabled / disabled in project settings' do
let(:project) { create(:project, :private, :repository) }
before do
project.add_developer(user)
create(:project_setting,
{ project: project,
forking_enabled: forking_enabled })
end
context 'forking is enabled' do
let(:forking_enabled) { true }
it 'enables fork button' do
visit project_path(project)
expect(page).to have_css('a', text: 'Fork')
expect(page).not_to have_css('a.disabled', text: 'Fork')
end
it 'renders new project fork page' do
visit new_project_fork_path(project)
expect(page.status_code).to eq(200)
expect(page).to have_text(' Select a namespace to fork the project ')
end
end
context 'forking is disabled' do
let(:forking_enabled) { false }
it 'does not render fork button' do
visit project_path(project)
expect(page).not_to have_css('a', text: 'Fork')
end
it 'does not render new project fork page' do
visit new_project_fork_path(project)
expect(page.status_code).to eq(403)
expect(page).to have_text('Forking is disabled for this project')
end
end
end
it 'forks the project', :sidekiq_might_not_need_inline do it 'forks the project', :sidekiq_might_not_need_inline do
visit project_path(project) visit project_path(project)
......
...@@ -34,6 +34,26 @@ describe 'Projects settings' do ...@@ -34,6 +34,26 @@ describe 'Projects settings' do
expect_toggle_state(:expanded) expect_toggle_state(:expanded)
end end
context 'forking enabled', :js do
it 'toggles forking enabled / disabled' do
visit edit_project_path(project)
forking_enabled_input = find('input[name="project[project_setting_attributes][forking_enabled]"]', visible: :hidden)
forking_enabled_button = find('input[name="project[project_setting_attributes][forking_enabled]"] + button')
expect(forking_enabled_input.value).to eq('true')
# disable by clicking toggle
forking_enabled_button.click
page.within('.sharing-permissions') do
find('input[value="Save changes"]').click
end
wait_for_requests
expect(forking_enabled_input.value).to eq('false')
end
end
def expect_toggle_state(state) def expect_toggle_state(state)
is_collapsed = state == :collapsed is_collapsed = state == :collapsed
......
...@@ -373,6 +373,7 @@ project: ...@@ -373,6 +373,7 @@ project:
- environments_for_dashboard - environments_for_dashboard
- deployments - deployments
- project_feature - project_feature
- project_setting
- auto_devops - auto_devops
- pages_domains - pages_domains
- authorized_users - authorized_users
......
...@@ -552,6 +552,12 @@ ProjectFeature: ...@@ -552,6 +552,12 @@ ProjectFeature:
- pages_access_level - pages_access_level
- created_at - created_at
- updated_at - updated_at
ProjectSetting:
- id
- project_id
- forking_enabled
- created_at
- updated_at
ProtectedBranch::MergeAccessLevel: ProtectedBranch::MergeAccessLevel:
- id - id
- protected_branch_id - protected_branch_id
......
# frozen_string_literal: true
require 'spec_helper'
describe ProjectSetting do
describe 'relations' do
it { is_expected.to belong_to(:project) }
end
describe 'validations' do
it { is_expected.to validate_inclusion_of(:forking_enabled).in_array([true, false]) }
end
end
...@@ -62,6 +62,7 @@ describe Project do ...@@ -62,6 +62,7 @@ describe Project do
it { is_expected.to have_one(:external_wiki_service) } it { is_expected.to have_one(:external_wiki_service) }
it { is_expected.to have_one(:project_feature) } it { is_expected.to have_one(:project_feature) }
it { is_expected.to have_one(:project_repository) } it { is_expected.to have_one(:project_repository) }
it { is_expected.to have_one(:project_setting) }
it { is_expected.to have_one(:container_expiration_policy) } it { is_expected.to have_one(:container_expiration_policy) }
it { is_expected.to have_one(:statistics).class_name('ProjectStatistics') } it { is_expected.to have_one(:statistics).class_name('ProjectStatistics') }
it { is_expected.to have_one(:import_data).class_name('ProjectImportData') } it { is_expected.to have_one(:import_data).class_name('ProjectImportData') }
......
...@@ -2858,6 +2858,20 @@ describe API::Projects do ...@@ -2858,6 +2858,20 @@ describe API::Projects do
expect(json_response['message']).to eq('401 Unauthorized') expect(json_response['message']).to eq('401 Unauthorized')
end end
end end
context 'forking disabled' do
before do
create(:project_setting,
{ project: project, forking_enabled: false })
end
it 'denies project to be forked' do
post api("/projects/#{project.id}/fork", admin)
expect(response).to have_gitlab_http_status(409)
expect(json_response['message']['forked_from_project_id']).to eq(['is forbidden'])
end
end
end end
describe 'POST /projects/:id/housekeeping' do describe 'POST /projects/:id/housekeeping' do
......
...@@ -224,6 +224,19 @@ describe Projects::ForkService do ...@@ -224,6 +224,19 @@ describe Projects::ForkService do
end end
end end
end end
context 'when forking is disabled' do
before do
create(:project_setting,
{ project: @from_project, forking_enabled: false })
end
it 'fails' do
to_project = fork_project(@from_project, @to_user, namespace: @to_user.namespace)
expect(to_project.errors[:forked_from_project_id]).to eq(['is forbidden'])
end
end
end end
describe 'fork to namespace' do describe 'fork to namespace' do
......
...@@ -8,8 +8,11 @@ describe Projects::UpdateService do ...@@ -8,8 +8,11 @@ describe Projects::UpdateService do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) do let(:project) do
create(:project, creator: user, namespace: user.namespace) create(:project, { creator: user,
namespace: user.namespace,
visibility_level: project_visibility_level })
end end
let(:project_visibility_level) { Gitlab::VisibilityLevel::PRIVATE }
describe '#execute' do describe '#execute' do
let(:gitlab_shell) { Gitlab::Shell.new } let(:gitlab_shell) { Gitlab::Shell.new }
...@@ -154,6 +157,40 @@ describe Projects::UpdateService do ...@@ -154,6 +157,40 @@ describe Projects::UpdateService do
end end
end end
context 'when changing forking enabled' do
subject do
update_project(project, user,
project_setting_attributes: { forking_enabled: forking_enabled } )
end
shared_examples 'valid forking_enabled change' do
it 'succeeds' do
expect(subject).to eq({ status: :success })
end
it 'updates the project' do
expect { subject }.to change(project, :forking_enabled).to(forking_enabled)
end
end
context 'enables forking' do
let(:forking_enabled) { true }
before do
create(:project_setting,
{ project: project, forking_enabled: false })
end
it_behaves_like 'valid forking_enabled change'
end
context 'disables forking' do
let(:forking_enabled) { false }
it_behaves_like 'valid forking_enabled change'
end
end
describe 'when updating project that has forks' do describe 'when updating project that has forks' do
let(:project) { create(:project, :internal) } let(:project) { create(:project, :internal) }
let(:forked_project) { fork_project(project) } let(:forked_project) { fork_project(project) }
......
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