2018-12-05 23:21:45 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
class Projects :: BranchesController < Projects :: ApplicationController
2015-04-26 12:48:37 +05:30
include ActionView :: Helpers :: SanitizeHelper
2016-09-13 17:45:13 +05:30
include SortingHelper
2017-08-17 22:00:37 +05:30
2014-09-02 18:07:02 +05:30
# Authorize
2017-08-17 22:00:37 +05:30
before_action :require_non_empty_project , except : :create
2015-09-11 14:41:01 +05:30
before_action :authorize_download_code!
2017-08-17 22:00:37 +05:30
before_action :authorize_push_code! , only : [ :new , :create , :destroy , :destroy_all_merged ]
2014-09-02 18:07:02 +05:30
2018-03-27 19:54:05 +05:30
# Support legacy URLs
before_action :redirect_for_legacy_index_sort_or_search , only : [ :index ]
2019-12-21 20:55:43 +05:30
before_action :limit_diverging_commit_counts! , only : [ :diverging_commit_counts ]
2016-09-29 09:46:39 +05:30
2021-01-03 14:25:43 +05:30
feature_category :source_code_management
2018-03-27 19:54:05 +05:30
def index
2016-09-29 09:46:39 +05:30
respond_to do | format |
2017-08-17 22:00:37 +05:30
format . html do
2018-03-27 19:54:05 +05:30
@sort = params [ :sort ] . presence || sort_value_recently_updated
@mode = params [ :state ] . presence || 'overview'
@overview_max_branches = 5
# Fetch branches for the specified mode
fetch_branches_by_mode
2019-02-15 15:39:39 +05:30
@refs_pipelines = @project . ci_pipelines . latest_successful_for_refs ( @branches . map ( & :name ) )
2018-05-09 12:01:36 +05:30
@merged_branch_names = repository . merged_branch_names ( @branches . map ( & :name ) )
2020-06-23 00:09:42 +05:30
@branch_pipeline_statuses = branch_pipeline_statuses
2018-05-09 12:01:36 +05:30
2020-06-23 00:09:42 +05:30
# https://gitlab.com/gitlab-org/gitlab/-/issues/22851
2018-11-08 19:23:39 +05:30
Gitlab :: GitalyClient . allow_n_plus_1_calls do
render
end
2017-08-17 22:00:37 +05:30
end
2016-09-29 09:46:39 +05:30
format . json do
2018-03-27 19:54:05 +05:30
branches = BranchesFinder . new ( @repository , params ) . execute
branches = Kaminari . paginate_array ( branches ) . page ( params [ :page ] )
render json : branches . map ( & :name )
2016-09-29 09:46:39 +05:30
end
end
2014-09-02 18:07:02 +05:30
end
def recent
@branches = @repository . recent_branches
end
2019-09-30 21:07:59 +05:30
def diverging_commit_counts
respond_to do | format |
format . json do
2020-01-01 13:55:28 +05:30
service = :: Branches :: DivergingCommitCountsService . new ( repository )
2019-09-30 21:07:59 +05:30
branches = BranchesFinder . new ( repository , params . permit ( names : [ ] ) ) . execute
Gitlab :: GitalyClient . allow_n_plus_1_calls do
2019-10-12 21:52:04 +05:30
render json : branches . map { | branch | [ branch . name , service . call ( branch ) ] } . to_h
2019-09-30 21:07:59 +05:30
end
end
end
end
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2014-09-02 18:07:02 +05:30
def create
2019-07-31 22:56:46 +05:30
branch_name = strip_tags ( sanitize ( params [ :branch_name ] ) )
2015-09-11 14:41:01 +05:30
branch_name = Addressable :: URI . unescape ( branch_name )
2016-06-02 11:05:42 +05:30
2018-03-17 18:26:18 +05:30
redirect_to_autodeploy = project . empty_repo? && project . deployment_platform . present?
2017-08-17 22:00:37 +05:30
2020-01-01 13:55:28 +05:30
result = :: Branches :: CreateService . new ( project , current_user )
2017-09-10 17:25:29 +05:30
. execute ( branch_name , ref )
2014-09-02 18:07:02 +05:30
2018-03-17 18:26:18 +05:30
success = ( result [ :status ] == :success )
if params [ :issue_iid ] && success
2019-09-30 21:07:59 +05:30
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-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
respond_to do | format |
format . html do
2018-03-17 18:26:18 +05:30
if success
2017-08-17 22:00:37 +05:30
if redirect_to_autodeploy
redirect_to url_to_autodeploy_setup ( project , branch_name ) ,
notice : view_context . autodeploy_flash_notice ( branch_name )
else
2017-09-10 17:25:29 +05:30
redirect_to project_tree_path ( @project , branch_name )
2017-08-17 22:00:37 +05:30
end
else
@error = result [ :message ]
render action : 'new'
end
end
format . json do
2018-03-17 18:26:18 +05:30
if success
2017-09-10 17:25:29 +05:30
render json : { name : branch_name , url : project_tree_url ( @project , branch_name ) }
2017-08-17 22:00:37 +05:30
else
render json : result [ :messsage ] , status : :unprocessable_entity
end
end
2015-04-26 12:48:37 +05:30
end
2014-09-02 18:07:02 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2014-09-02 18:07:02 +05:30
def destroy
2015-09-11 14:41:01 +05:30
@branch_name = Addressable :: URI . unescape ( params [ :id ] )
2020-01-01 13:55:28 +05:30
result = :: Branches :: DeleteService . new ( project , current_user ) . execute ( @branch_name )
2017-09-10 17:25:29 +05:30
2014-09-02 18:07:02 +05:30
respond_to do | format |
2015-04-26 12:48:37 +05:30
format . html do
2019-07-31 22:56:46 +05:30
flash_type = result . error? ? :alert : :notice
flash [ flash_type ] = result . message
2017-09-10 17:25:29 +05:30
2018-11-18 11:00:15 +05:30
redirect_to project_branches_path ( @project ) , status : :see_other
2015-04-26 12:48:37 +05:30
end
2017-08-17 22:00:37 +05:30
2019-07-31 22:56:46 +05:30
format . js { head result . http_status }
format . json { render json : { message : result . message } , status : result . http_status }
2014-09-02 18:07:02 +05:30
end
end
2016-06-02 11:05:42 +05:30
2017-08-17 22:00:37 +05:30
def destroy_all_merged
2020-01-01 13:55:28 +05:30
:: Branches :: DeleteMergedService . new ( @project , current_user ) . async_execute
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
redirect_to project_branches_path ( @project ) ,
2019-07-07 11:18:12 +05:30
notice : _ ( 'Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.' )
2017-08-17 22:00:37 +05:30
end
2016-06-02 11:05:42 +05:30
private
2019-12-21 20:55:43 +05:30
# 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-06-02 11:05:42 +05:30
def ref
if params [ :ref ]
2019-07-31 22:56:46 +05:30
ref_escaped = strip_tags ( sanitize ( params [ :ref ] ) )
2016-06-02 11:05:42 +05:30
Addressable :: URI . unescape ( ref_escaped )
else
2017-08-17 22:00:37 +05:30
@project . default_branch || 'master'
2016-06-02 11:05:42 +05:30
end
end
2017-08-17 22:00:37 +05:30
def url_to_autodeploy_setup ( project , branch_name )
2017-09-10 17:25:29 +05:30
project_new_blob_path (
2017-08-17 22:00:37 +05:30
project ,
branch_name ,
file_name : '.gitlab-ci.yml' ,
commit_message : 'Set up auto deploy' ,
target_branch : branch_name ,
context : 'autodeploy'
)
end
2018-03-27 19:54:05 +05:30
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-07-07 11:18:12 +05:30
redirect_to project_branches_filtered_path ( @project , state : 'all' ) , notice : _ ( 'Update your bookmarked URLs as filtered/sorted branches URL has been changed.' )
2018-03-27 19:54:05 +05:30
end
end
def fetch_branches_by_mode
if @mode == 'overview'
# overview mode
@active_branches , @stale_branches = BranchesFinder . new ( @repository , sort : sort_value_recently_updated ) . execute . partition ( & :active? )
# Here we get one more branch to indicate if there are more data we're not showing
@active_branches = @active_branches . first ( @overview_max_branches + 1 )
@stale_branches = @stale_branches . first ( @overview_max_branches + 1 )
@branches = @active_branches + @stale_branches
else
# active/stale/all view mode
@branches = BranchesFinder . new ( @repository , params . merge ( sort : @sort ) ) . execute
@branches = @branches . select { | b | b . state . to_s == @mode } if %w[ active stale ] . include? ( @mode )
@branches = Kaminari . paginate_array ( @branches ) . page ( params [ :page ] )
end
end
2019-09-30 21:07:59 +05:30
def confidential_issue_project
return if params [ :confidential_issue_project_id ] . blank?
confidential_issue_project = Project . find ( params [ :confidential_issue_project_id ] )
return unless can? ( current_user , :update_issue , confidential_issue_project )
confidential_issue_project
end
2020-06-23 00:09:42 +05:30
def branch_pipeline_statuses
latest_commits = @branches . map do | branch |
[ branch . name , repository . commit ( branch . dereferenced_target ) . sha ]
end . to_h
latest_pipelines = project . ci_pipelines . latest_pipeline_per_commit ( latest_commits . values )
latest_commits . transform_values do | commit_sha |
latest_pipelines [ commit_sha ] & . detailed_status ( current_user )
end . compact
end
2014-09-02 18:07:02 +05:30
end