2018-09-26 03:45:43 +00:00
# frozen_string_literal: true
2013-07-16 19:19:07 +00:00
class Projects :: BranchesController < Projects :: ApplicationController
2014-11-13 15:20:43 +00:00
include ActionView :: Helpers :: SanitizeHelper
2016-08-10 19:15:22 +00:00
include SortingHelper
2017-02-06 16:59:54 +00:00
2013-07-16 19:19:07 +00:00
# Authorize
2017-02-06 16:59:54 +00:00
before_action :require_non_empty_project , except : :create
2015-04-16 12:03:37 +00:00
before_action :authorize_download_code!
2016-09-21 14:15:12 +00:00
before_action :authorize_push_code! , only : [ :new , :create , :destroy , :destroy_all_merged ]
2013-07-16 19:19:07 +00:00
2017-11-15 14:56:36 +00:00
# Support legacy URLs
before_action :redirect_for_legacy_index_sort_or_search , only : [ :index ]
2019-10-01 00:06:42 +00:00
before_action :limit_diverging_commit_counts! , only : [ :diverging_commit_counts ]
2016-02-12 18:42:25 +00:00
2020-10-08 18:08:32 +00:00
feature_category :source_code_management
2017-11-15 14:56:36 +00:00
def index
2016-08-01 19:56:56 +00:00
respond_to do | format |
2016-12-22 06:21:40 +00:00
format . html do
2017-11-15 14:56:36 +00:00
@mode = params [ :state ] . presence || 'overview'
2020-12-16 12:09:53 +00:00
@sort = sort_value_for_mode
2017-11-15 14:56:36 +00:00
@overview_max_branches = 5
# Fetch branches for the specified mode
fetch_branches_by_mode
2018-12-05 14:39:15 +00:00
@refs_pipelines = @project . ci_pipelines . latest_successful_for_refs ( @branches . map ( & :name ) )
2018-03-26 15:57:13 +00:00
@merged_branch_names = repository . merged_branch_names ( @branches . map ( & :name ) )
2020-10-30 03:08:51 +00:00
@branch_pipeline_statuses = Ci :: CommitStatusesFinder . new ( @project , repository , current_user , @branches ) . execute
2018-04-02 09:40:27 +00:00
2020-06-15 00:08:43 +00:00
# https://gitlab.com/gitlab-org/gitlab/-/issues/22851
2018-06-14 11:01:55 +00:00
Gitlab :: GitalyClient . allow_n_plus_1_calls do
render
end
2016-12-22 06:21:40 +00:00
end
2016-08-01 19:56:56 +00:00
format . json do
2017-11-15 14:56:36 +00:00
branches = BranchesFinder . new ( @repository , params ) . execute
branches = Kaminari . paginate_array ( branches ) . page ( params [ :page ] )
render json : branches . map ( & :name )
2016-08-01 19:56:56 +00:00
end
end
2013-07-16 19:19:07 +00:00
end
2019-06-18 14:20:11 +00:00
def diverging_commit_counts
respond_to do | format |
format . json do
2019-12-03 18:06:49 +00:00
service = :: Branches :: DivergingCommitCountsService . new ( repository )
2019-06-18 14:20:11 +00:00
branches = BranchesFinder . new ( repository , params . permit ( names : [ ] ) ) . execute
Gitlab :: GitalyClient . allow_n_plus_1_calls do
2021-03-28 15:09:30 +00:00
render json : branches . to_h { | branch | [ branch . name , service . call ( branch ) ] }
2019-06-18 14:20:11 +00:00
end
end
end
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2013-07-16 19:19:07 +00:00
def create
2019-04-11 12:24:13 +00:00
branch_name = strip_tags ( sanitize ( params [ :branch_name ] ) )
2015-08-02 06:33:33 +00:00
branch_name = Addressable :: URI . unescape ( branch_name )
2016-02-12 18:42:25 +00:00
2017-11-27 13:35:16 +00:00
redirect_to_autodeploy = project . empty_repo? && project . deployment_platform . present?
2017-02-06 16:59:54 +00:00
2019-12-03 18:06:49 +00:00
result = :: Branches :: CreateService . new ( project , current_user )
2017-06-21 13:48:12 +00:00
. execute ( branch_name , ref )
2014-10-30 15:28:59 +00:00
2017-12-27 17:58:46 +00:00
success = ( result [ :status ] == :success )
if params [ :issue_iid ] && success
2019-06-28 22:08:26 +00:00
target_project = confidential_issue_project || @project
issue = IssuesFinder . new ( current_user , project_id : target_project . id ) . find_by ( iid : params [ :issue_iid ] )
SystemNoteService . new_issue_branch ( issue , target_project , current_user , branch_name , branch_project : @project ) if issue
2016-02-17 06:11:48 +00:00
end
2017-05-04 08:09:21 +00:00
respond_to do | format |
format . html do
2017-12-27 17:58:46 +00:00
if success
2017-05-04 08:09:21 +00:00
if redirect_to_autodeploy
redirect_to url_to_autodeploy_setup ( project , branch_name ) ,
notice : view_context . autodeploy_flash_notice ( branch_name )
else
2017-06-29 17:06:35 +00:00
redirect_to project_tree_path ( @project , branch_name )
2017-05-04 08:09:21 +00:00
end
else
@error = result [ :message ]
render action : 'new'
end
end
2017-02-06 16:59:54 +00:00
2017-05-04 08:09:21 +00:00
format . json do
2017-12-27 17:58:46 +00:00
if success
2017-06-29 17:06:35 +00:00
render json : { name : branch_name , url : project_tree_url ( @project , branch_name ) }
2017-05-04 08:09:21 +00:00
else
render json : result [ :messsage ] , status : :unprocessable_entity
end
2017-02-06 16:59:54 +00:00
end
2014-07-27 14:40:00 +00:00
end
2013-07-16 19:19:07 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2013-07-16 19:19:07 +00:00
def destroy
2015-08-02 06:33:33 +00:00
@branch_name = Addressable :: URI . unescape ( params [ :id ] )
2019-12-03 18:06:49 +00:00
result = :: Branches :: DeleteService . new ( project , current_user ) . execute ( @branch_name )
2017-05-08 07:41:58 +00:00
2013-07-16 19:19:07 +00:00
respond_to do | format |
2015-01-24 18:02:58 +00:00
format . html do
2019-04-19 15:39:12 +00:00
flash_type = result . error? ? :alert : :notice
flash [ flash_type ] = result . message
2017-05-08 07:41:58 +00:00
2018-07-02 10:43:06 +00:00
redirect_to project_branches_path ( @project ) , status : :see_other
2015-01-24 18:02:58 +00:00
end
2017-05-08 07:41:58 +00:00
2019-04-19 15:39:12 +00:00
format . js { head result . http_status }
format . json { render json : { message : result . message } , status : result . http_status }
2013-07-16 19:19:07 +00:00
end
end
2016-02-12 18:42:25 +00:00
2016-09-21 14:15:12 +00:00
def destroy_all_merged
2019-12-03 18:06:49 +00:00
:: Branches :: DeleteMergedService . new ( @project , current_user ) . async_execute
2016-09-21 14:15:12 +00:00
2017-06-29 17:06:35 +00:00
redirect_to project_branches_path ( @project ) ,
2019-03-27 16:52:52 +00:00
notice : _ ( 'Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.' )
2016-09-21 14:15:12 +00:00
end
2016-02-12 18:42:25 +00:00
private
2020-12-16 12:09:53 +00:00
def sort_value_for_mode
return params [ :sort ] if params [ :sort ] . present?
'stale' == @mode ? sort_value_oldest_updated : sort_value_recently_updated
end
2019-10-01 00:06:42 +00:00
# It can be expensive to calculate the diverging counts for each
# branch. Normally the frontend should be specifying a set of branch
# names, but prior to
# https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/32496, the
# frontend could omit this set. To prevent excessive I/O, we require
# that a list of names be specified.
def limit_diverging_commit_counts!
limit = Kaminari . config . default_per_page
# If we don't have many branches in the repository, then go ahead.
return if project . repository . branch_count < = limit
return if params [ :names ] . present? && Array ( params [ :names ] ) . length < = limit
render json : { error : " Specify at least one and at most #{ limit } branch names " } , status : :unprocessable_entity
end
2016-02-12 18:42:25 +00:00
def ref
if params [ :ref ]
2019-04-11 12:24:13 +00:00
ref_escaped = strip_tags ( sanitize ( params [ :ref ] ) )
2016-02-12 18:42:25 +00:00
Addressable :: URI . unescape ( ref_escaped )
else
2021-05-25 18:10:42 +00:00
@project . default_branch_or_main
2016-02-12 18:42:25 +00:00
end
end
2017-02-07 15:59:38 +00:00
def url_to_autodeploy_setup ( project , branch_name )
2017-06-29 17:06:35 +00:00
project_new_blob_path (
2017-02-07 15:59:38 +00:00
project ,
branch_name ,
file_name : '.gitlab-ci.yml' ,
commit_message : 'Set up auto deploy' ,
target_branch : branch_name ,
context : 'autodeploy'
)
end
2017-11-15 14:56:36 +00:00
def redirect_for_legacy_index_sort_or_search
# Normalize a legacy URL with redirect
if request . format != :json && ! params [ :state ] . presence && [ :sort , :search , :page ] . any? { | key | params [ key ] . presence }
2019-03-27 16:52:52 +00:00
redirect_to project_branches_filtered_path ( @project , state : 'all' ) , notice : _ ( 'Update your bookmarked URLs as filtered/sorted branches URL has been changed.' )
2017-11-15 14:56:36 +00:00
end
end
def fetch_branches_by_mode
2020-12-16 12:09:53 +00:00
return fetch_branches_for_overview if @mode == 'overview'
2021-02-08 21:09:25 +00:00
@branches , @prev_path , @next_path =
Projects :: BranchesByModeService . new ( @project , params . merge ( sort : @sort , mode : @mode ) ) . execute
2020-12-16 12:09:53 +00:00
end
def fetch_branches_for_overview
# Here we get one more branch to indicate if there are more data we're not showing
limit = @overview_max_branches + 1
2021-05-27 21:10:59 +00:00
@active_branches =
BranchesFinder . new ( @repository , { per_page : limit , sort : sort_value_recently_updated } )
. execute ( gitaly_pagination : true ) . select ( & :active? )
@stale_branches =
BranchesFinder . new ( @repository , { per_page : limit , sort : sort_value_oldest_updated } )
. execute ( gitaly_pagination : true ) . select ( & :stale? )
2020-12-16 12:09:53 +00:00
@branches = @active_branches + @stale_branches
2017-11-15 14:56:36 +00:00
end
2019-06-19 08:56:17 +00:00
def confidential_issue_project
return if params [ :confidential_issue_project_id ] . blank?
confidential_issue_project = Project . find ( params [ :confidential_issue_project_id ] )
2019-07-01 08:23:23 +00:00
return unless can? ( current_user , :update_issue , confidential_issue_project )
2019-06-19 08:56:17 +00:00
confidential_issue_project
end
2013-07-16 19:19:07 +00:00
end