diff options
author | Douwe Maan <douwe@gitlab.com> | 2015-10-19 11:34:48 +0200 |
---|---|---|
committer | Douwe Maan <douwe@gitlab.com> | 2015-10-19 11:34:48 +0200 |
commit | 7ae139566b46050b31bf01a6302af560fc129819 (patch) | |
tree | cc342c422373d89d12aa763a8a924d241192b4a1 | |
parent | a32f7766098bf38b1028168b4919516460a562e9 (diff) | |
parent | 8adeda37b55fc992e3cb15422cae5d9646640630 (diff) | |
download | gitlab-ce-7ae139566b46050b31bf01a6302af560fc129819.tar.gz |
Merge branch 'master' into full-width-tablesfull-width-tables
35 files changed, 291 insertions, 96 deletions
diff --git a/CHANGELOG b/CHANGELOG index abf9ead6df7..f8daa6d246c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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) - Show last project commit to default branch on project home page - 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) + - 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 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 diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index c2118abbf55..35db00281e5 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -10,6 +10,10 @@ border-bottom: 1px solid #E7E9EE; margin-bottom: 1em; + &.readme-holder { + border-bottom: 0; + } + table { @extend .table; } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index a27763ad8f4..41bea0ec5c8 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -544,5 +544,5 @@ pre.light-well { } .project-show-readme .readme-holder { - padding: 7px; + border-top: 0; } diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index b19b710472d..1b0cef481d6 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -1,11 +1,4 @@ .tree-holder { - .tree_progress { - display: none; - margin: 20px; - &.loading { - display: block; - } - } .tree-table { margin-bottom: 0; diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 213c2a7173b..73200396ecc 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,11 +1,14 @@ class ProjectsController < ApplicationController + include ExtractsPath + prepend_before_filter :render_go_import, only: [:show] skip_before_action :authenticate_user!, only: [:show, :activity] before_action :project, except: [:new, :create] before_action :repository, except: [:new, :create] + before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists? # 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] layout :determine_layout @@ -56,6 +59,8 @@ class ProjectsController < ApplicationController end def transfer + return access_denied! unless can?(current_user, :change_namespace, @project) + namespace = Namespace.find_by(id: params[:new_namespace_id]) ::Projects::TransferService.new(project, current_user).execute(namespace) @@ -64,6 +69,15 @@ class ProjectsController < ApplicationController 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 respond_to do |format| format.html @@ -139,6 +153,7 @@ class ProjectsController < ApplicationController def archive return access_denied! unless can?(current_user, :archive_project, @project) + @project.archive! respond_to do |format| @@ -148,6 +163,7 @@ class ProjectsController < ApplicationController def unarchive return access_denied! unless can?(current_user, :archive_project, @project) + @project.unarchive! respond_to do |format| @@ -225,4 +241,12 @@ class ProjectsController < ApplicationController render "go_import", layout: false end + + def repo_exists? + project.repository_exists? && !project.empty_repo? + end + + def get_id + project.repository.root_ref + end end diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index 4710171ebaa..c73cb3028ee 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -34,7 +34,8 @@ module PreferencesHelper def project_view_choices [ ['Readme (default)', :readme], - ['Activity view', :activity] + ['Activity view', :activity], + ['Files view', :files] ] end @@ -46,8 +47,7 @@ module PreferencesHelper Gitlab::ColorSchemes.for_user(current_user).css_class end - def prefer_readme? - !current_user || - current_user.project_view == 'readme' + def default_project_view + current_user ? current_user.project_view : 'readme' end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index dd5e3828da2..5301c2ccf76 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -70,6 +70,10 @@ module ProjectsHelper "You are going to transfer #{project.name_with_namespace} to another owner. Are you ABSOLUTELY sure?" 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 @nav_tabs ||= get_project_nav_tabs(@project, current_user) end diff --git a/app/models/ability.rb b/app/models/ability.rb index 38bc2086683..b72178fa126 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -189,7 +189,8 @@ class Ability :change_visibility_level, :rename_project, :remove_project, - :archive_project + :archive_project, + :remove_fork_project ] end diff --git a/app/models/user.rb b/app/models/user.rb index 3b346c55edb..7e4321d5376 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -183,7 +183,7 @@ class User < ActiveRecord::Base # User's Project preference # 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 diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index e54044365b9..3de7bb9dcaa 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -79,7 +79,7 @@ class GitPushService authors = Hash.new do |hash, commit| 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) end diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb index aceb8cb9021..8f25c5e2496 100644 --- a/app/services/merge_requests/post_merge_service.rb +++ b/app/services/merge_requests/post_merge_service.rb @@ -6,6 +6,7 @@ module MergeRequests # class PostMergeService < MergeRequests::BaseService def execute(merge_request) + close_issues(merge_request) merge_request.mark_as_merged create_merge_event(merge_request, current_user) create_note(merge_request) @@ -15,6 +16,15 @@ module MergeRequests 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) EventCreateService.new.merge_mr(merge_request, current_user) end diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index 01e285a8dfa..cc41d7dd813 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -38,7 +38,7 @@ .col-sm-10 = f.select :layout, layout_choices, {}, class: 'form-control' .help-block - Choose between fixed (max. 1200px) and fluid (100%) application layout + Choose between fixed (max. 1200px) and fluid (100%) application layout. .form-group = f.label :dashboard, class: 'control-label' do Default Dashboard @@ -52,6 +52,6 @@ .col-sm-10 = f.select :project_view, project_view_choices, {}, class: 'form-control' .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 = f.submit 'Save', class: 'btn btn-save' diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml index c2683bc6219..012858f70b4 100644 --- a/app/views/projects/_activity.html.haml +++ b/app/views/projects/_activity.html.haml @@ -1,4 +1,3 @@ -= render 'projects/last_push' .gray-content-block.activity-filter-block - if current_user .pull-right diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml new file mode 100644 index 00000000000..fa978325ddd --- /dev/null +++ b/app/views/projects/_files.html.haml @@ -0,0 +1,6 @@ +#tree-holder.tree-holder.clearfix + .gray-content-block.second-block + = render 'projects/tree/tree_header', tree: @tree + + = render 'projects/tree/tree_content', tree: @tree + diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml index 5bc1999ec9d..0a1cecfdcdf 100644 --- a/app/views/projects/_readme.html.haml +++ b/app/views/projects/_readme.html.haml @@ -1,12 +1,11 @@ - if readme = @repository.readme - %article.readme-holder#README - .clearfix - .pull-right - - - if can?(current_user, :push_code, @project) - = link_to namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light' do - %i.fa-align.fa.fa-pencil - .wiki + %article.file-holder.readme-holder + .file-title + = blob_icon readme.mode, readme.name + = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)) do + %strong + = readme.name + .file-content.wiki = cache(readme_cache_key) do = render_readme(readme) - else diff --git a/app/views/projects/activity.html.haml b/app/views/projects/activity.html.haml index 555ed76426d..69fa4ad37c4 100644 --- a/app/views/projects/activity.html.haml +++ b/app/views/projects/activity.html.haml @@ -1,4 +1,6 @@ - page_title "Activity" - header_title project_title(@project, "Activity", activity_project_path(@project)) += render 'projects/last_push' + = render 'projects/activity' diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml index a1ae1397584..42f632b38ef 100644 --- a/app/views/projects/blob/_blob.html.haml +++ b/app/views/projects/blob/_blob.html.haml @@ -1,19 +1,22 @@ -%ul.breadcrumb.repo-breadcrumb - %li - %i.fa.fa-angle-right - = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do - = @project.path - - tree_breadcrumbs(@tree, 6) do |title, path| +.gray-content-block.top-block + .tree-ref-holder + = render 'shared/ref_switcher', destination: 'blob', path: @path + + %ul.breadcrumb.repo-breadcrumb %li - - if path - - if path.end_with?(@path) - = link_to namespace_project_blob_path(@project.namespace, @project, path) do - %strong - = truncate(title, length: 40) + = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do + = @project.path + - tree_breadcrumbs(@tree, 6) do |title, path| + %li + - 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 - = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path) - - else - = link_to title, '#' + = link_to title, '#' %ul.blob-commit-info.hidden-xs - blob_commit = @repository.last_commit_for_path(@commit.id, blob.path) diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml index fa4be4a1bc4..f52b89f6921 100644 --- a/app/views/projects/blob/show.html.haml +++ b/app/views/projects/blob/show.html.haml @@ -3,9 +3,6 @@ = render 'projects/last_push' -%div.tree-ref-holder - = render 'shared/ref_switcher', destination: 'blob', path: @path - %div#tree-holder.tree-holder = render 'blob', blob: @blob diff --git a/app/views/projects/ci_services/index.html.haml b/app/views/projects/ci_services/index.html.haml index c78b21884a3..c164b2d4bc0 100644 --- a/app/views/projects/ci_services/index.html.haml +++ b/app/views/projects/ci_services/index.html.haml @@ -6,7 +6,7 @@ %tr %th %th Service - %th Desription + %th Description %th Last edit - @services.sort_by(&:title).each do |service| %tr diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 1882a82fba5..afbf88b5507 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -189,6 +189,21 @@ - else .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) .panel.panel-default.panel.panel-danger .panel-heading Remove project @@ -201,7 +216,8 @@ = button_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) } - 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 .center diff --git a/app/views/projects/remove_fork.js.haml b/app/views/projects/remove_fork.js.haml new file mode 100644 index 00000000000..17b9fecfeb1 --- /dev/null +++ b/app/views/projects/remove_fork.js.haml @@ -0,0 +1,2 @@ +:plain + location.href = "#{edit_namespace_project_path(@project.namespace, @project)}"; diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index e20b1fc49c0..585caf674c9 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -7,8 +7,7 @@ = render 'shared/no_ssh' = render 'shared/no_password' -- if prefer_readme? - = render 'projects/last_push' += render 'projects/last_push' = render "home_panel" @@ -28,7 +27,7 @@ = link_to project_files_path(@project) do = repository_size - - if !prefer_readme? && @repository.readme + - if default_project_view != 'readme' && @repository.readme %li = link_to 'Readme', readme_path(@project) @@ -68,14 +67,8 @@ .content-block.second-block.white = render 'projects/last_commit', commit: @repository.commit, project: @project -%section - - if prefer_readme? - .project-show-readme - = render 'projects/readme' - - else - .project-show-activity - = render 'projects/activity' - +%div{class: "project-show-#{default_project_view}"} + = render default_project_view - if current_user - access = user_max_access_in_project(current_user, @project) diff --git a/app/views/projects/tree/_blob_item.html.haml b/app/views/projects/tree/_blob_item.html.haml index 02ecbade219..2ddc5d504fa 100644 --- a/app/views/projects/tree/_blob_item.html.haml +++ b/app/views/projects/tree/_blob_item.html.haml @@ -4,5 +4,5 @@ %span.str-truncated = 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 - = render 'spinner' + = render 'projects/tree/spinner' %td.hidden-xs.tree_commit diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml index 7e9af19c8ba..3c5edf4b033 100644 --- a/app/views/projects/tree/_readme.html.haml +++ b/app/views/projects/tree/_readme.html.haml @@ -1,8 +1,8 @@ -%article.file-holder.readme-holder#README +%article.file-holder.readme-holder .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 - %i.fa.fa-file = readme.name .file-content.wiki = render_readme(readme) diff --git a/app/views/projects/tree/_tree.html.haml b/app/views/projects/tree/_tree_content.html.haml index b5510199ad1..a5e478a38fd 100644 --- a/app/views/projects/tree/_tree.html.haml +++ b/app/views/projects/tree/_tree_content.html.haml @@ -29,7 +29,7 @@ = icon('folder fw') New directory -%div#tree-content-holder.tree-content-holder +%div.tree-content-holder .table-holder %table.table#tree-slider{class: "table_#{@hex_path} tree-table table-striped" } %thead @@ -60,8 +60,6 @@ - if tree.readme = render "projects/tree/readme", readme: tree.readme -%div.tree_progress - - 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/new_dir' diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml new file mode 100644 index 00000000000..1115ca6b4ca --- /dev/null +++ b/app/views/projects/tree/_tree_header.html.haml @@ -0,0 +1,32 @@ +.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 diff --git a/app/views/projects/tree/_tree_item.html.haml b/app/views/projects/tree/_tree_item.html.haml index e87138bf980..cf65057e704 100644 --- a/app/views/projects/tree/_tree_item.html.haml +++ b/app/views/projects/tree/_tree_item.html.haml @@ -5,5 +5,5 @@ - path = flatten_tree(tree_item) = link_to path, namespace_project_tree_path(@project.namespace, @project, tree_join(@id || @commit.id, path)) %td.tree_time_ago.cgray - = render 'spinner' + = render 'projects/tree/spinner' %td.hidden-xs.tree_commit diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml index dec4677f830..ec14bd7f65a 100644 --- a/app/views/projects/tree/show.html.haml +++ b/app/views/projects/tree/show.html.haml @@ -6,12 +6,12 @@ = render 'projects/last_push' -.tree-ref-holder - = render 'shared/ref_switcher', destination: 'tree', path: @path - - if can? current_user, :download_code, @project .tree-download-holder = 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 - = render "tree", tree: @tree + .gray-content-block.top-block + = render 'projects/tree/tree_header', tree: @tree + + = render 'projects/tree/tree_content', tree: @tree diff --git a/config/routes.rb b/config/routes.rb index 3dbe2c4dfcc..f6812c9280a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -378,6 +378,7 @@ Gitlab::Application.routes.draw do [:new, :create, :index], path: "/") do member do put :transfer + delete :remove_fork post :archive post :unarchive post :toggle_star diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb index 15f77734cb2..d76891d5bde 100644 --- a/features/steps/project/project.rb +++ b/features/steps/project/project.rb @@ -86,13 +86,13 @@ class Spinach::Features::Project < Spinach::FeatureSteps end 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' end end step 'I should see project "Shop" README' do - page.within('#README') do + page.within('.readme-holder') do expect(page).to have_content 'testme' end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index c2fb36b4143..67ee66a2058 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -246,8 +246,8 @@ module API # Example Request: # DELETE /projects/:id/fork delete ":id/fork" do - authenticated_as_admin! - unless user_project.forked_project_link.nil? + authorize! :remove_fork_project, user_project + if user_project.forked? user_project.forked_project_link.destroy end end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 333bd059055..da8df8a3025 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -27,7 +27,7 @@ module Gitlab def references @references ||= Hash.new do |references, type| 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) end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 21beaf37fce..4460bf12f96 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -22,6 +22,34 @@ describe ProjectsController do 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 it "redirects to the normalized path for case mismatch" do get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase @@ -62,4 +90,50 @@ describe ProjectsController do expect(user.starred?(public_project)).to be_falsey 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 diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index aac93b17a38..09fcff2444a 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -34,6 +34,27 @@ feature 'Project', feature: true do 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 let(:user) { create(:user) } let(:project) { create(:project, namespace: user.namespace) } @@ -45,13 +66,13 @@ feature 'Project', feature: true do end 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 - def remove_project - click_button "Remove project" - fill_in 'confirm_name_input', with: project.path + def remove_with_confirm(button_text, confirm_with) + click_button button_text + fill_in 'confirm_name_input', with: confirm_with click_button 'Confirm' end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 580bbec77d1..e9de9e0826d 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -606,28 +606,42 @@ describe API::API, api: true 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) - expect(response.status).to eq(403) + expect(response.status).to eq(404) 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 + context 'when users belong to project group' do + let(:project_fork_target) { create(:project, group: create(:group)) } - 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 + before do + project_fork_target.group.add_owner user + project_fork_target.group.add_developer user2 + end + + 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 |