Commit 7ae13956 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into full-width-tables

parents a32f7766 8adeda37
...@@ -3,8 +3,10 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -3,8 +3,10 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.2.0 (unreleased) v 8.2.0 (unreleased)
- Show last project commit to default branch on project home page - Show last project commit to default branch on project home page
- Highlight comment based on anchor in URL - Highlight comment based on anchor in URL
- Adds ability to remove the forked relationship from project settings screen. (Han Loong Liauw)
v 8.1.0 (unreleased) v 8.1.0 (unreleased)
- Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge.
- Fix nonatomic database update potentially causing project star counts to go negative (Stan Hu) - Fix nonatomic database update potentially causing project star counts to go negative (Stan Hu)
- Fix error preventing displaying of commit data for a directory with a leading dot (Stan Hu) - Fix error preventing displaying of commit data for a directory with a leading dot (Stan Hu)
- Speed up load times of issue detail pages by roughly 1.5x - Speed up load times of issue detail pages by roughly 1.5x
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
border-bottom: 1px solid #E7E9EE; border-bottom: 1px solid #E7E9EE;
margin-bottom: 1em; margin-bottom: 1em;
&.readme-holder {
border-bottom: 0;
}
table { table {
@extend .table; @extend .table;
} }
......
...@@ -544,5 +544,5 @@ pre.light-well { ...@@ -544,5 +544,5 @@ pre.light-well {
} }
.project-show-readme .readme-holder { .project-show-readme .readme-holder {
padding: 7px; border-top: 0;
} }
.tree-holder { .tree-holder {
.tree_progress {
display: none;
margin: 20px;
&.loading {
display: block;
}
}
.tree-table { .tree-table {
margin-bottom: 0; margin-bottom: 0;
......
class ProjectsController < ApplicationController class ProjectsController < ApplicationController
include ExtractsPath
prepend_before_filter :render_go_import, only: [:show] prepend_before_filter :render_go_import, only: [:show]
skip_before_action :authenticate_user!, only: [:show, :activity] skip_before_action :authenticate_user!, only: [:show, :activity]
before_action :project, except: [:new, :create] before_action :project, except: [:new, :create]
before_action :repository, except: [:new, :create] before_action :repository, except: [:new, :create]
before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists?
# Authorize # Authorize
before_action :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive] before_action :authorize_admin_project!, only: [:edit, :update]
before_action :event_filter, only: [:show, :activity] before_action :event_filter, only: [:show, :activity]
layout :determine_layout layout :determine_layout
...@@ -56,6 +59,8 @@ class ProjectsController < ApplicationController ...@@ -56,6 +59,8 @@ class ProjectsController < ApplicationController
end end
def transfer def transfer
return access_denied! unless can?(current_user, :change_namespace, @project)
namespace = Namespace.find_by(id: params[:new_namespace_id]) namespace = Namespace.find_by(id: params[:new_namespace_id])
::Projects::TransferService.new(project, current_user).execute(namespace) ::Projects::TransferService.new(project, current_user).execute(namespace)
...@@ -64,6 +69,15 @@ class ProjectsController < ApplicationController ...@@ -64,6 +69,15 @@ class ProjectsController < ApplicationController
end end
end end
def remove_fork
return access_denied! unless can?(current_user, :remove_fork_project, @project)
if @project.forked?
@project.forked_project_link.destroy
flash[:notice] = 'The fork relationship has been removed.'
end
end
def activity def activity
respond_to do |format| respond_to do |format|
format.html format.html
...@@ -139,6 +153,7 @@ class ProjectsController < ApplicationController ...@@ -139,6 +153,7 @@ class ProjectsController < ApplicationController
def archive def archive
return access_denied! unless can?(current_user, :archive_project, @project) return access_denied! unless can?(current_user, :archive_project, @project)
@project.archive! @project.archive!
respond_to do |format| respond_to do |format|
...@@ -148,6 +163,7 @@ class ProjectsController < ApplicationController ...@@ -148,6 +163,7 @@ class ProjectsController < ApplicationController
def unarchive def unarchive
return access_denied! unless can?(current_user, :archive_project, @project) return access_denied! unless can?(current_user, :archive_project, @project)
@project.unarchive! @project.unarchive!
respond_to do |format| respond_to do |format|
...@@ -225,4 +241,12 @@ class ProjectsController < ApplicationController ...@@ -225,4 +241,12 @@ class ProjectsController < ApplicationController
render "go_import", layout: false render "go_import", layout: false
end end
def repo_exists?
project.repository_exists? && !project.empty_repo?
end
def get_id
project.repository.root_ref
end
end end
...@@ -34,7 +34,8 @@ module PreferencesHelper ...@@ -34,7 +34,8 @@ module PreferencesHelper
def project_view_choices def project_view_choices
[ [
['Readme (default)', :readme], ['Readme (default)', :readme],
['Activity view', :activity] ['Activity view', :activity],
['Files view', :files]
] ]
end end
...@@ -46,8 +47,7 @@ module PreferencesHelper ...@@ -46,8 +47,7 @@ module PreferencesHelper
Gitlab::ColorSchemes.for_user(current_user).css_class Gitlab::ColorSchemes.for_user(current_user).css_class
end end
def prefer_readme? def default_project_view
!current_user || current_user ? current_user.project_view : 'readme'
current_user.project_view == 'readme'
end end
end end
...@@ -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 source project #{@project.forked_from_project.name_with_namespace}. 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
......
...@@ -189,7 +189,8 @@ class Ability ...@@ -189,7 +189,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
......
...@@ -183,7 +183,7 @@ class User < ActiveRecord::Base ...@@ -183,7 +183,7 @@ class User < ActiveRecord::Base
# User's Project preference # User's Project preference
# Note: When adding an option, it MUST go on the end of the array. # Note: When adding an option, it MUST go on the end of the array.
enum project_view: [:readme, :activity] enum project_view: [:readme, :activity, :files]
alias_attribute :private_token, :authentication_token alias_attribute :private_token, :authentication_token
......
...@@ -79,7 +79,7 @@ class GitPushService ...@@ -79,7 +79,7 @@ class GitPushService
authors = Hash.new do |hash, commit| authors = Hash.new do |hash, commit|
email = commit.author_email email = commit.author_email
return hash[email] if hash.has_key?(email) next hash[email] if hash.has_key?(email)
hash[email] = commit_user(commit) hash[email] = commit_user(commit)
end end
......
...@@ -6,6 +6,7 @@ module MergeRequests ...@@ -6,6 +6,7 @@ module MergeRequests
# #
class PostMergeService < MergeRequests::BaseService class PostMergeService < MergeRequests::BaseService
def execute(merge_request) def execute(merge_request)
close_issues(merge_request)
merge_request.mark_as_merged merge_request.mark_as_merged
create_merge_event(merge_request, current_user) create_merge_event(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
...@@ -15,6 +16,15 @@ module MergeRequests ...@@ -15,6 +16,15 @@ module MergeRequests
private private
def close_issues(merge_request)
return unless merge_request.target_branch == project.default_branch
closed_issues = merge_request.closes_issues(current_user)
closed_issues.each do |issue|
Issues::CloseService.new(project, current_user, {}).execute(issue, merge_request)
end
end
def create_merge_event(merge_request, current_user) def create_merge_event(merge_request, current_user)
EventCreateService.new.merge_mr(merge_request, current_user) EventCreateService.new.merge_mr(merge_request, current_user)
end end
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
.col-sm-10 .col-sm-10
= f.select :layout, layout_choices, {}, class: 'form-control' = f.select :layout, layout_choices, {}, class: 'form-control'
.help-block .help-block
Choose between fixed (max. 1200px) and fluid (100%) application layout Choose between fixed (max. 1200px) and fluid (100%) application layout.
.form-group .form-group
= f.label :dashboard, class: 'control-label' do = f.label :dashboard, class: 'control-label' do
Default Dashboard Default Dashboard
...@@ -52,6 +52,6 @@ ...@@ -52,6 +52,6 @@
.col-sm-10 .col-sm-10
= f.select :project_view, project_view_choices, {}, class: 'form-control' = f.select :project_view, project_view_choices, {}, class: 'form-control'
.help-block .help-block
Choose what content you want to see when visit project page Choose what content you want to see on a project's home page.
.panel-footer .panel-footer
= f.submit 'Save', class: 'btn btn-save' = f.submit 'Save', class: 'btn btn-save'
= render 'projects/last_push'
.gray-content-block.activity-filter-block .gray-content-block.activity-filter-block
- if current_user - if current_user
.pull-right .pull-right
......
#tree-holder.tree-holder.clearfix
.gray-content-block.second-block
= render 'projects/tree/tree_header', tree: @tree
= render 'projects/tree/tree_content', tree: @tree
- if readme = @repository.readme - if readme = @repository.readme
%article.readme-holder#README %article.file-holder.readme-holder
.clearfix .file-title
.pull-right = blob_icon readme.mode, readme.name
&nbsp; = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)) do
- if can?(current_user, :push_code, @project) %strong
= link_to namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light' do = readme.name
%i.fa-align.fa.fa-pencil .file-content.wiki
.wiki
= cache(readme_cache_key) do = cache(readme_cache_key) do
= render_readme(readme) = render_readme(readme)
- else - else
......
- page_title "Activity" - page_title "Activity"
- header_title project_title(@project, "Activity", activity_project_path(@project)) - header_title project_title(@project, "Activity", activity_project_path(@project))
= render 'projects/last_push'
= render 'projects/activity' = render 'projects/activity'
%ul.breadcrumb.repo-breadcrumb .gray-content-block.top-block
%li .tree-ref-holder
%i.fa.fa-angle-right = render 'shared/ref_switcher', destination: 'blob', path: @path
= link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
= @project.path %ul.breadcrumb.repo-breadcrumb
- tree_breadcrumbs(@tree, 6) do |title, path|
%li %li
- if path = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
- if path.end_with?(@path) = @project.path
= link_to namespace_project_blob_path(@project.namespace, @project, path) do - tree_breadcrumbs(@tree, 6) do |title, path|
%strong %li
= truncate(title, length: 40) - if path
- if path.end_with?(@path)
= link_to namespace_project_blob_path(@project.namespace, @project, path) do
%strong
= truncate(title, length: 40)
- else
= link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
- else - else
= link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path) = link_to title, '#'
- else
= link_to title, '#'
%ul.blob-commit-info.hidden-xs %ul.blob-commit-info.hidden-xs
- blob_commit = @repository.last_commit_for_path(@commit.id, blob.path) - blob_commit = @repository.last_commit_for_path(@commit.id, blob.path)
......
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
= render 'projects/last_push' = render 'projects/last_push'
%div.tree-ref-holder
= render 'shared/ref_switcher', destination: 'blob', path: @path
%div#tree-holder.tree-holder %div#tree-holder.tree-holder
= render 'blob', blob: @blob = render 'blob', blob: @blob
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
%tr %tr
%th %th
%th Service %th Service
%th Desription %th Description
%th Last edit %th Last edit
- @services.sort_by(&:title).each do |service| - @services.sort_by(&:title).each do |service|
%tr %tr
......
...@@ -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?
- if can?(current_user, :remove_fork_project, @project)
= form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :delete, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
.panel.panel-default.panel.panel-danger
.panel-heading Remove fork relationship
.panel-body
%p
This will remove the fork relationship to source project
#{link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)}.
%br
%strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
= button_to 'Remove fork relationship', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_message(@project) }
- else
.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
...@@ -201,7 +216,8 @@ ...@@ -201,7 +216,8 @@
= button_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) } = button_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) }
- else - else
.nothing-here-block Only project owner can remove a project .nothing-here-block Only the project owner can remove a project.
.save-project-loader.hide .save-project-loader.hide
.center .center
......
:plain
location.href = "#{edit_namespace_project_path(@project.namespace, @project)}";
...@@ -7,8 +7,7 @@ ...@@ -7,8 +7,7 @@
= render 'shared/no_ssh' = render 'shared/no_ssh'
= render 'shared/no_password' = render 'shared/no_password'
- if prefer_readme? = render 'projects/last_push'
= render 'projects/last_push'
= render "home_panel" = render "home_panel"
...@@ -28,7 +27,7 @@ ...@@ -28,7 +27,7 @@
= link_to project_files_path(@project) do = link_to project_files_path(@project) do
= repository_size = repository_size
- if !prefer_readme? && @repository.readme - if default_project_view != 'readme' && @repository.readme
%li %li
= link_to 'Readme', readme_path(@project) = link_to 'Readme', readme_path(@project)
...@@ -68,14 +67,8 @@ ...@@ -68,14 +67,8 @@
.content-block.second-block.white .content-block.second-block.white
= render 'projects/last_commit', commit: @repository.commit, project: @project = render 'projects/last_commit', commit: @repository.commit, project: @project
%section %div{class: "project-show-#{default_project_view}"}
- if prefer_readme? = render default_project_view
.project-show-readme
= render 'projects/readme'
- else
.project-show-activity
= render 'projects/activity'
- if current_user - if current_user
- access = user_max_access_in_project(current_user, @project) - access = user_max_access_in_project(current_user, @project)
......
...@@ -4,5 +4,5 @@ ...@@ -4,5 +4,5 @@
%span.str-truncated %span.str-truncated
= link_to blob_item.name, namespace_project_blob_path(@project.namespace, @project, tree_join(@id || @commit.id, blob_item.name)) = link_to blob_item.name, namespace_project_blob_path(@project.namespace, @project, tree_join(@id || @commit.id, blob_item.name))
%td.tree_time_ago.cgray %td.tree_time_ago.cgray
= render 'spinner' = render 'projects/tree/spinner'
%td.hidden-xs.tree_commit %td.hidden-xs.tree_commit
%article.file-holder.readme-holder#README %article.file-holder.readme-holder
.file-title .file-title
= link_to '#README' do = blob_icon readme.mode, readme.name
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)) do
%strong %strong
%i.fa.fa-file
= readme.name = readme.name
.file-content.wiki .file-content.wiki
= render_readme(readme) = render_readme(readme)
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
= icon('folder fw') = icon('folder fw')
New directory New directory
%div#tree-content-holder.tree-content-holder %div.tree-content-holder
.table-holder .table-holder
%table.table#tree-slider{class: "table_#{@hex_path} tree-table table-striped" } %table.table#tree-slider{class: "table_#{@hex_path} tree-table table-striped" }
%thead %thead
...@@ -60,8 +60,6 @@ ...@@ -60,8 +60,6 @@
- if tree.readme - if tree.readme
= render "projects/tree/readme", readme: tree.readme = render "projects/tree/readme", readme: tree.readme
%div.tree_progress
- if allowed_tree_edit? - if allowed_tree_edit?
= render 'projects/blob/upload', title: 'Upload', placeholder: 'Upload new file', button_title: 'Upload file', form_path: namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post = render 'projects/blob/upload', title: 'Upload', placeholder: 'Upload new file', button_title: 'Upload file', form_path: namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post
= render 'projects/blob/new_dir' = render 'projects/blob/new_dir'
......
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'tree', path: @path
%ul.breadcrumb.repo-breadcrumb
%li
= link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
= @project.path
- tree_breadcrumbs(tree, 6) do |title, path|
%li
- if path
= link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
- else
= link_to title, '#'
- if allowed_tree_edit?
%li
%span.dropdown
%a.dropdown-toggle.btn.add-to-tree{href: '#', "data-toggle" => "dropdown"}
= icon('plus')
%ul.dropdown-menu
%li
= link_to namespace_project_new_blob_path(@project.namespace, @project, @id), title: 'Create file', id: 'new-file-link' do
= icon('pencil fw')
Create file
%li
= link_to '#modal-upload-blob', { 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal'} do
= icon('file fw')
Upload file
%li.divider
%li
= link_to '#modal-create-new-dir', { 'data-target' => '#modal-create-new-dir', 'data-toggle' => 'modal'} do
= icon('folder fw')
New directory
...@@ -5,5 +5,5 @@ ...@@ -5,5 +5,5 @@
- path = flatten_tree(tree_item) - path = flatten_tree(tree_item)
= link_to path, namespace_project_tree_path(@project.namespace, @project, tree_join(@id || @commit.id, path)) = link_to path, namespace_project_tree_path(@project.namespace, @project, tree_join(@id || @commit.id, path))
%td.tree_time_ago.cgray %td.tree_time_ago.cgray
= render 'spinner' = render 'projects/tree/spinner'
%td.hidden-xs.tree_commit %td.hidden-xs.tree_commit
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
= render 'projects/last_push' = render 'projects/last_push'
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'tree', path: @path
- if can? current_user, :download_code, @project - if can? current_user, :download_code, @project
.tree-download-holder .tree-download-holder
= render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group pull-right hidden-xs hidden-sm', split_button: true = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group pull-right hidden-xs hidden-sm', split_button: true
#tree-holder.tree-holder.clearfix #tree-holder.tree-holder.clearfix
= render "tree", tree: @tree .gray-content-block.top-block
= render 'projects/tree/tree_header', tree: @tree
= render 'projects/tree/tree_content', tree: @tree
...@@ -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
delete :remove_fork
post :archive post :archive
post :unarchive post :unarchive
post :toggle_star post :toggle_star
......
...@@ -86,13 +86,13 @@ class Spinach::Features::Project < Spinach::FeatureSteps ...@@ -86,13 +86,13 @@ class Spinach::Features::Project < Spinach::FeatureSteps
end end
step 'I should see project "Forum" README' do step 'I should see project "Forum" README' do
page.within('#README') do page.within('.readme-holder') do
expect(page).to have_content 'Sample repo for testing gitlab features' expect(page).to have_content 'Sample repo for testing gitlab features'
end end
end end
step 'I should see project "Shop" README' do step 'I should see project "Shop" README' do
page.within('#README') do page.within('.readme-holder') do
expect(page).to have_content 'testme' expect(page).to have_content 'testme'
end end
end end
......
...@@ -246,8 +246,8 @@ module API ...@@ -246,8 +246,8 @@ module API
# Example Request: # Example Request:
# DELETE /projects/:id/fork # DELETE /projects/:id/fork
delete ":id/fork" do delete ":id/fork" do
authenticated_as_admin! authorize! :remove_fork_project, user_project
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
......
...@@ -27,7 +27,7 @@ module Gitlab ...@@ -27,7 +27,7 @@ module Gitlab
def references def references
@references ||= Hash.new do |references, type| @references ||= Hash.new do |references, type|
type = type.to_sym type = type.to_sym
return references[type] if references.has_key?(type) next references[type] if references.has_key?(type)
references[type] = pipeline_result(type) references[type] = pipeline_result(type)
end end
......
...@@ -22,6 +22,34 @@ describe ProjectsController do ...@@ -22,6 +22,34 @@ describe ProjectsController do
end end
end end
context "rendering default project view" do
render_views
it "renders the activity view" do
allow(controller).to receive(:current_user).and_return(user)
allow(user).to receive(:project_view).and_return('activity')
get :show, namespace_id: public_project.namespace.path, id: public_project.path
expect(response).to render_template('_activity')
end
it "renders the readme view" do
allow(controller).to receive(:current_user).and_return(user)
allow(user).to receive(:project_view).and_return('readme')
get :show, namespace_id: public_project.namespace.path, id: public_project.path
expect(response).to render_template('_readme')
end
it "renders the files view" do
allow(controller).to receive(:current_user).and_return(user)
allow(user).to receive(:project_view).and_return('files')
get :show, namespace_id: public_project.namespace.path, id: public_project.path
expect(response).to render_template('_files')
end
end
context "when requested with case sensitive namespace and project path" do context "when requested with case sensitive namespace and project path" do
it "redirects to the normalized path for case mismatch" do it "redirects to the normalized path for case mismatch" do
get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase
...@@ -62,4 +90,50 @@ describe ProjectsController do ...@@ -62,4 +90,50 @@ describe ProjectsController do
expect(user.starred?(public_project)).to be_falsey expect(user.starred?(public_project)).to be_falsey
end end
end end
describe "DELETE 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) }
before do
create(:forked_project_link, forked_to_project: project_fork)
end
it 'should remove fork from project' do
delete(: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('The fork relationship has been removed.')
expect(response).to render_template(:remove_fork)
end
end
context 'when project not forked' do
let(:unforked_project) { create(:project, namespace: user.namespace) }
it 'should do nothing if project was not forked' do
delete(: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
end
it "does nothing if user is not signed in" do
delete(: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 fork relationship'
remove_with_confirm('Remove fork relationship', project.path)
expect(page).to have_content 'The fork relationship has been removed.'
expect(project.forked?).to be_falsey
expect(page).not_to have_content 'Remove fork 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
...@@ -606,28 +606,42 @@ describe API::API, api: true do ...@@ -606,28 +606,42 @@ describe API::API, api: true do
describe 'DELETE /projects/:id/fork' do describe 'DELETE /projects/:id/fork' do
it "shouldn't available for non admin users" do it "shouldn't be visible to users outside group" do
delete api("/projects/#{project_fork_target.id}/fork", user) delete api("/projects/#{project_fork_target.id}/fork", user)
expect(response.status).to eq(403) expect(response.status).to eq(404)
end end
it 'should make forked project unforked' do context 'when users belong to project group' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) let(:project_fork_target) { create(:project, group: create(:group)) }
project_fork_target.reload
expect(project_fork_target.forked_from_project).not_to be_nil
expect(project_fork_target.forked?).to be_truthy
delete api("/projects/#{project_fork_target.id}/fork", admin)
expect(response.status).to eq(200)
project_fork_target.reload
expect(project_fork_target.forked_from_project).to be_nil
expect(project_fork_target.forked?).not_to be_truthy
end
it 'should be idempotent if not forked' do before do
expect(project_fork_target.forked_from_project).to be_nil project_fork_target.group.add_owner user
delete api("/projects/#{project_fork_target.id}/fork", admin) project_fork_target.group.add_developer user2
expect(response.status).to eq(200) end
expect(project_fork_target.reload.forked_from_project).to be_nil
it 'should be forbidden to non-owner users' do
delete api("/projects/#{project_fork_target.id}/fork", user2)
expect(response.status).to eq(403)
end
it 'should make forked project unforked' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
project_fork_target.reload
expect(project_fork_target.forked_from_project).not_to be_nil
expect(project_fork_target.forked?).to be_truthy
delete api("/projects/#{project_fork_target.id}/fork", admin)
expect(response.status).to eq(200)
project_fork_target.reload
expect(project_fork_target.forked_from_project).to be_nil
expect(project_fork_target.forked?).not_to be_truthy
end
it 'should be idempotent if not forked' do
expect(project_fork_target.forked_from_project).to be_nil
delete api("/projects/#{project_fork_target.id}/fork", admin)
expect(response.status).to eq(200)
expect(project_fork_target.reload.forked_from_project).to be_nil
end
end end
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