Commit c9871e84 authored by Francisco Javier López's avatar Francisco Javier López Committed by Douwe Maan

The API isn't using the appropriate services for managing forks

parent af09fb85
module Projects
class ForkService < BaseService
def execute
def execute(fork_to_project = nil)
if fork_to_project
link_existing_project(fork_to_project)
else
fork_new_project
end
end
private
def link_existing_project(fork_to_project)
return if fork_to_project.forked?
link_fork_network(fork_to_project)
fork_to_project
end
def fork_new_project
new_params = {
forked_from_project_id: @project.id,
visibility_level: allowed_visibility_level,
......@@ -21,15 +39,11 @@ module Projects
builds_access_level = @project.project_feature.builds_access_level
new_project.project_feature.update_attributes(builds_access_level: builds_access_level)
refresh_forks_count
link_fork_network(new_project)
new_project
end
private
def fork_network
if @project.fork_network
@project.fork_network
......@@ -43,9 +57,17 @@ module Projects
end
end
def link_fork_network(new_project)
fork_network.fork_network_members.create(project: new_project,
def link_fork_network(fork_to_project)
fork_network.fork_network_members.create(project: fork_to_project,
forked_from_project: @project)
# TODO: remove this when ForkedProjectLink model is removed
unless fork_to_project.forked_project_link
fork_to_project.create_forked_project_link(forked_to_project: fork_to_project,
forked_from_project: @project)
end
refresh_forks_count
end
def refresh_forks_count
......
---
title: Using appropiate services in the API for managing forks
merge_request: 15709
author:
type: fixed
class RescheduleForkNetworkCreationCaller < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'PopulateForkNetworksRange'.freeze
BATCH_SIZE = 100
DELAY_INTERVAL = 15.seconds
disable_ddl_transaction!
class ForkedProjectLink < ActiveRecord::Base
include EachBatch
self.table_name = 'forked_project_links'
end
def up
say 'Populating the `fork_networks` based on existing `forked_project_links`'
queue_background_migration_jobs_by_range_at_intervals(ForkedProjectLink, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
end
def down
# nothing
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20171124150326) do
ActiveRecord::Schema.define(version: 20171205190711) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......
......@@ -367,15 +367,16 @@ module API
post ":id/fork/:forked_from_id" do
authenticated_as_admin!
forked_from_project = find_project!(params[:forked_from_id])
not_found!("Source Project") unless forked_from_project
fork_from_project = find_project!(params[:forked_from_id])
if user_project.forked_from_project.nil?
user_project.create_forked_project_link(forked_to_project_id: user_project.id, forked_from_project_id: forked_from_project.id)
not_found!("Source Project") unless fork_from_project
::Projects::ForksCountService.new(forked_from_project).refresh_cache
result = ::Projects::ForkService.new(fork_from_project, current_user).execute(user_project)
if result
present user_project.reload, with: Entities::Project
else
render_api_error!("Project already forked", 409)
render_api_error!("Project already forked", 409) if user_project.forked?
end
end
......@@ -383,11 +384,11 @@ module API
delete ":id/fork" do
authorize! :remove_fork_project, user_project
if user_project.forked?
destroy_conditionally!(user_project.forked_project_link)
else
not_modified!
result = destroy_conditionally!(user_project) do
::Projects::UnlinkForkService.new(user_project, current_user).execute
end
result ? status(204) : not_modified!
end
desc 'Share the project with a group' do
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe Projects::ForkService do
include ProjectForksHelper
let(:gitlab_shell) { Gitlab::Shell.new }
context 'when forking a new project' do
describe 'fork by user' do
before do
@from_user = create(:user)
......@@ -210,4 +210,47 @@ describe Projects::ForkService do
end
end
end
end
context 'when linking fork to an existing project' do
let(:fork_from_project) { create(:project, :public) }
let(:fork_to_project) { create(:project, :public) }
let(:user) { create(:user) }
subject { described_class.new(fork_from_project, user) }
def forked_from_project(project)
project.fork_network_member&.forked_from_project
end
context 'if project is already forked' do
it 'does not create fork relation' do
allow(fork_to_project).to receive(:forked?).and_return(true)
expect(forked_from_project(fork_to_project)).to be_nil
expect(subject.execute(fork_to_project)).to be_nil
expect(forked_from_project(fork_to_project)).to be_nil
end
end
context 'if project is not forked' do
it 'creates fork relation' do
expect(fork_to_project.forked?).to be false
expect(forked_from_project(fork_to_project)).to be_nil
subject.execute(fork_to_project)
expect(fork_to_project.forked?).to be true
expect(forked_from_project(fork_to_project)).to eq fork_from_project
expect(fork_to_project.forked_from_project).to eq fork_from_project
end
it 'flushes the forks count cache of the source project' do
expect(fork_from_project.forks_count).to be_zero
subject.execute(fork_to_project)
expect(fork_from_project.forks_count).to eq(1)
end
end
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