Commit df99ddbb authored by Han Loong Liauw's avatar Han Loong Liauw

Adds ability to remove the forked relationship

This was previously possible through the API but can now be done
through the project#edit settings screen if the current user is
the owner of the project.
Update changelog
parent e12b6f30
...@@ -45,6 +45,8 @@ v 8.1.0 (unreleased) ...@@ -45,6 +45,8 @@ v 8.1.0 (unreleased)
- Fix position of hamburger in header for smaller screens (Han Loong Liauw) - Fix position of hamburger in header for smaller screens (Han Loong Liauw)
- Fix bug where Emojis in Markdown would truncate remaining text (Sakata Sinji) - Fix bug where Emojis in Markdown would truncate remaining text (Sakata Sinji)
- Persist filters when sorting on admin user page (Jerry Lukins) - Persist filters when sorting on admin user page (Jerry Lukins)
- Adds ability to remove the forked relationship from project settings
screen. #2578 (Han Loong Liauw)
v 8.0.4 v 8.0.4
- Fix Message-ID header to be RFC 2111-compliant to prevent e-mails being dropped (Stan Hu) - Fix Message-ID header to be RFC 2111-compliant to prevent e-mails being dropped (Stan Hu)
......
...@@ -5,7 +5,7 @@ class ProjectsController < ApplicationController ...@@ -5,7 +5,7 @@ class ProjectsController < ApplicationController
before_action :repository, except: [:new, :create] before_action :repository, except: [:new, :create]
# Authorize # Authorize
before_action :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive] before_action :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive, :remove_fork]
before_action :event_filter, only: [:show, :activity] before_action :event_filter, only: [:show, :activity]
layout :determine_layout layout :determine_layout
...@@ -64,6 +64,13 @@ class ProjectsController < ApplicationController ...@@ -64,6 +64,13 @@ class ProjectsController < ApplicationController
end end
end end
def remove_fork
if @project.forked?
@project.forked_project_link.destroy
flash[:notice] = 'Fork relationship has been removed.'
end
end
def activity def activity
respond_to do |format| respond_to do |format|
format.html format.html
......
...@@ -70,6 +70,10 @@ module ProjectsHelper ...@@ -70,6 +70,10 @@ module ProjectsHelper
"You are going to transfer #{project.name_with_namespace} to another owner. Are you ABSOLUTELY sure?" "You are going to transfer #{project.name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
end end
def remove_fork_project_message(project)
"You are going to remove the fork relationship to the source project from #{@project.forked_from_project.namespace.try(:name)}. Are you ABSOLUTELY sure?"
end
def project_nav_tabs def project_nav_tabs
@nav_tabs ||= get_project_nav_tabs(@project, current_user) @nav_tabs ||= get_project_nav_tabs(@project, current_user)
end end
......
...@@ -185,7 +185,8 @@ class Ability ...@@ -185,7 +185,8 @@ class Ability
:change_visibility_level, :change_visibility_level,
:rename_project, :rename_project,
:remove_project, :remove_project,
:archive_project :archive_project,
:remove_fork_project
] ]
end end
......
...@@ -189,6 +189,21 @@ ...@@ -189,6 +189,21 @@
- else - else
.nothing-here-block Only the project owner can transfer a project .nothing-here-block Only the project owner can transfer a project
- if @project.forked? && can?(current_user, :remove_fork_project, @project)
= form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :put, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
.panel.panel-default.panel.panel-danger
.panel-heading Remove forked relationship
.panel-body
%p
This will remove the relationship to the source project from
= link_to project_path(@project.forked_from_project) do
= @project.forked_from_project.namespace.try(:name)
%br
%strong Once removed it cannot be reversed through this interface
= button_to 'Remove forked relationship', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_message(@project) }
- elsif @project.forked?
.nothing-here-block Only the project owner can remove the fork relationship
- if can?(current_user, :remove_project, @project) - if can?(current_user, :remove_project, @project)
.panel.panel-default.panel.panel-danger .panel.panel-default.panel.panel-danger
.panel-heading Remove project .panel-heading Remove project
...@@ -203,6 +218,7 @@ ...@@ -203,6 +218,7 @@
- else - else
.nothing-here-block Only project owner can remove a project .nothing-here-block Only project owner can remove a project
.save-project-loader.hide .save-project-loader.hide
.center .center
%h2 %h2
......
:plain
location.href = "#{edit_namespace_project_path(@project.namespace, @project)}";
...@@ -378,6 +378,7 @@ Gitlab::Application.routes.draw do ...@@ -378,6 +378,7 @@ Gitlab::Application.routes.draw do
[:new, :create, :index], path: "/") do [:new, :create, :index], path: "/") do
member do member do
put :transfer put :transfer
put :remove_fork
post :archive post :archive
post :unarchive post :unarchive
post :toggle_star post :toggle_star
......
...@@ -247,7 +247,7 @@ module API ...@@ -247,7 +247,7 @@ module API
# DELETE /projects/:id/fork # DELETE /projects/:id/fork
delete ":id/fork" do delete ":id/fork" do
authenticated_as_admin! authenticated_as_admin!
unless user_project.forked_project_link.nil? if user_project.forked?
user_project.forked_project_link.destroy user_project.forked_project_link.destroy
end end
end end
......
...@@ -62,4 +62,44 @@ describe ProjectsController do ...@@ -62,4 +62,44 @@ describe ProjectsController do
expect(user.starred?(public_project)).to be_falsey expect(user.starred?(public_project)).to be_falsey
end end
end end
describe "PUT remove_fork" do
context 'when signed in' do
before do
sign_in(user)
end
context 'with forked project' do
let(:project_fork) { create(:project, namespace: user.namespace) }
it 'should remove fork from project' do
create(:forked_project_link, forked_to_project: project_fork)
put(:remove_fork,
namespace_id: project_fork.namespace.to_param,
id: project_fork.to_param, format: :js)
expect(project_fork.forked?).to be_falsey
expect(flash[:notice]).to eq('Fork relationship has been removed.')
expect(response).to render_template(:remove_fork)
end
end
it 'should do nothing if project was not forked' do
unforked_project = create(:project, namespace: user.namespace)
put(:remove_fork,
namespace_id: unforked_project.namespace.to_param,
id: unforked_project.to_param, format: :js)
expect(flash[:notice]).to be_nil
expect(response).to render_template(:remove_fork)
end
end
it "does nothing if user is not signed in" do
put(:remove_fork,
namespace_id: project.namespace.to_param,
id: project.to_param, format: :js)
expect(response.status).to eq(401)
end
end
end end
...@@ -34,6 +34,27 @@ feature 'Project', feature: true do ...@@ -34,6 +34,27 @@ feature 'Project', feature: true do
end end
end end
describe 'remove forked relationship', js: true do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
before do
login_with user
create(:forked_project_link, forked_to_project: project)
visit edit_namespace_project_path(project.namespace, project)
end
it 'should remove fork' do
expect(page).to have_content 'Remove forked relationship'
remove_with_confirm('Remove forked relationship', project.path)
expect(page).to have_content 'Fork relationship has been removed.'
expect(project.forked?).to be_falsey
expect(page).not_to have_content 'Remove forked relationship'
end
end
describe 'removal', js: true do describe 'removal', js: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) } let(:project) { create(:project, namespace: user.namespace) }
...@@ -45,13 +66,13 @@ feature 'Project', feature: true do ...@@ -45,13 +66,13 @@ feature 'Project', feature: true do
end end
it 'should remove project' do it 'should remove project' do
expect { remove_project }.to change {Project.count}.by(-1) expect { remove_with_confirm('Remove project', project.path) }.to change {Project.count}.by(-1)
end end
end end
def remove_project def remove_with_confirm(button_text, confirm_with)
click_button "Remove project" click_button button_text
fill_in 'confirm_name_input', with: project.path fill_in 'confirm_name_input', with: confirm_with
click_button 'Confirm' click_button 'Confirm'
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