2018-12-05 23:21:45 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
module ProjectsHelper
2022-07-23 23:45:48 +05:30
include Gitlab :: Utils :: StrongMemoize
2023-06-20 00:43:36 +05:30
include CompareHelper
2023-07-09 08:55:56 +05:30
include Gitlab :: Allowable
2022-07-23 23:45:48 +05:30
2020-03-13 15:44:24 +05:30
def project_incident_management_setting
@project_incident_management_setting || = @project . incident_management_setting ||
@project . build_incident_management_setting
end
2015-04-26 12:48:37 +05:30
def link_to_project ( project )
2020-11-24 15:15:51 +05:30
link_to namespace_project_path ( namespace_id : project . namespace , id : project ) , title : h ( project . name ) , class : 'gl-link' do
2014-09-02 18:07:02 +05:30
title = content_tag ( :span , project . name , class : 'project-name' )
if project . namespace
namespace = content_tag ( :span , " #{ project . namespace . human_name } / " , class : 'namespace-name' )
title = namespace + title
end
title
end
end
2016-04-02 18:10:28 +05:30
def link_to_member_avatar ( author , opts = { } )
2021-11-18 22:05:49 +05:30
default_opts = { size : 16 }
2016-04-02 18:10:28 +05:30
opts = default_opts . merge ( opts )
2018-03-17 18:26:18 +05:30
classes = %W[ avatar avatar-inline s #{ opts [ :size ] } ]
classes << opts [ :avatar_class ] if opts [ :avatar_class ]
2018-03-27 19:54:05 +05:30
avatar = avatar_icon_for_user ( author , opts [ :size ] )
2018-03-17 18:26:18 +05:30
2021-11-18 22:05:49 +05:30
image_tag ( avatar , width : opts [ :size ] , class : classes , alt : '' )
2018-03-17 18:26:18 +05:30
end
def author_content_tag ( author , opts = { } )
default_opts = { author_class : 'author' , tooltip : false , by_username : false }
opts = default_opts . merge ( opts )
has_tooltip = ! opts [ :by_username ] && opts [ :tooltip ]
username = opts [ :by_username ] ? author . to_reference : author . name
name_tag_options = { class : [ opts [ :author_class ] ] }
if has_tooltip
name_tag_options [ :title ] = author . to_reference
name_tag_options [ :data ] = { placement : 'top' }
name_tag_options [ :class ] << 'has-tooltip'
end
2018-06-27 16:04:02 +05:30
# NOTE: ActionView::Helpers::TagHelper#content_tag HTML escapes username
content_tag ( :span , username , name_tag_options )
2016-04-02 18:10:28 +05:30
end
2016-06-02 11:05:42 +05:30
def link_to_member ( project , author , opts = { } , & block )
2018-03-17 18:26:18 +05:30
default_opts = { avatar : true , name : true , title : " :name " }
2014-09-02 18:07:02 +05:30
opts = default_opts . merge ( opts )
2022-04-04 11:22:00 +05:30
return " (deleted) " unless author
2019-02-15 15:39:39 +05:30
data_attrs = {
user_id : author . id ,
username : author . username ,
name : author . name
}
2022-04-04 11:22:00 +05:30
inject_classes = [ " author-link " , opts [ :extra_class ] ]
2014-09-02 18:07:02 +05:30
2022-04-04 11:22:00 +05:30
if opts [ :name ]
inject_classes . concat ( [ " js-user-link " , opts [ :mobile_classes ] ] )
else
2023-01-13 00:05:48 +05:30
inject_classes . append ( " has-tooltip " )
2022-04-04 11:22:00 +05:30
end
inject_classes = inject_classes . compact . join ( " " )
2014-09-02 18:07:02 +05:30
2022-04-04 11:22:00 +05:30
author_html = [ ]
2014-09-02 18:07:02 +05:30
# Build avatar image tag
2018-03-17 18:26:18 +05:30
author_html << link_to_member_avatar ( author , opts ) if opts [ :avatar ]
2014-09-02 18:07:02 +05:30
# Build name span tag
2018-03-17 18:26:18 +05:30
author_html << author_content_tag ( author , opts ) if opts [ :name ]
2016-06-02 11:05:42 +05:30
author_html << capture ( & block ) if block
2018-12-05 23:21:45 +05:30
author_html = author_html . join . html_safe
2014-09-02 18:07:02 +05:30
if opts [ :name ]
2022-04-04 11:22:00 +05:30
link_to ( author_html , user_path ( author ) , class : inject_classes , data : data_attrs ) . html_safe
2014-09-02 18:07:02 +05:30
else
2015-12-23 02:04:40 +05:30
title = opts [ :title ] . sub ( " :name " , sanitize ( author . name ) )
2022-04-04 11:22:00 +05:30
link_to ( author_html , user_path ( author ) , class : inject_classes , title : title , data : { container : 'body' , qa_selector : 'assignee_link' } ) . html_safe
2014-09-02 18:07:02 +05:30
end
end
2017-08-17 22:00:37 +05:30
def project_title ( project )
2021-01-29 00:20:46 +05:30
namespace_link = build_namespace_breadcrumb_link ( project )
project_link = build_project_breadcrumb_link ( project )
2016-04-02 18:10:28 +05:30
2018-03-17 18:26:18 +05:30
namespace_link = breadcrumb_list_item ( namespace_link ) unless project . group
project_link = breadcrumb_list_item project_link
2015-09-25 12:07:36 +05:30
2018-03-17 18:26:18 +05:30
" #{ namespace_link } #{ project_link } " . html_safe
2014-09-02 18:07:02 +05:30
end
def remove_project_message ( project )
2020-10-24 23:57:45 +05:30
_ ( " You are going to delete %{project_full_name}. Deleted projects CANNOT be restored! Are you ABSOLUTELY sure? " ) %
2018-03-27 19:54:05 +05:30
{ project_full_name : project . full_name }
2014-09-02 18:07:02 +05:30
end
2015-04-26 12:48:37 +05:30
def transfer_project_message ( project )
2020-11-24 15:15:51 +05:30
_ ( " You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure? " ) %
2018-03-27 19:54:05 +05:30
{ project_full_name : project . full_name }
2015-04-26 12:48:37 +05:30
end
2019-12-04 20:38:33 +05:30
def remove_fork_project_description_message ( project )
source = visible_fork_source ( project )
2018-03-17 18:26:18 +05:30
2019-12-04 20:38:33 +05:30
if source
2020-01-01 13:55:28 +05:30
msg = _ ( 'This will remove the fork relationship between this project and %{fork_source}.' ) %
2019-12-04 20:38:33 +05:30
{ fork_source : link_to ( source . full_name , project_path ( source ) ) }
2020-01-01 13:55:28 +05:30
msg . html_safe
2018-03-17 18:26:18 +05:30
else
2019-12-04 20:38:33 +05:30
_ ( 'This will remove the fork relationship between this project and other projects in the fork network.' )
2018-03-17 18:26:18 +05:30
end
2015-11-26 14:37:03 +05:30
end
2023-04-23 21:23:45 +05:30
def vue_fork_divergence_data ( project , ref )
source_project = visible_fork_source ( project )
return { } unless source_project
source_default_branch = source_project . default_branch
2023-07-09 08:55:56 +05:30
merge_request =
MergeRequest . opened
. from_project ( project ) . of_projects ( source_project . id ) . from_source_branches ( ref ) . first
2023-04-23 21:23:45 +05:30
{
2023-06-20 00:43:36 +05:30
project_path : project . full_path ,
selected_branch : ref ,
2023-04-23 21:23:45 +05:30
source_name : source_project . full_name ,
source_path : project_path ( source_project ) ,
2023-05-27 22:25:52 +05:30
source_default_branch : source_default_branch ,
2023-07-09 08:55:56 +05:30
can_sync_branch : can_sync_branch? ( project , ref ) . to_s ,
2023-04-23 21:23:45 +05:30
ahead_compare_path : project_compare_path (
project , from : source_default_branch , to : ref , from_project_id : source_project . id
) ,
2023-07-09 08:55:56 +05:30
create_mr_path : create_merge_request_path ( project , source_project , ref , merge_request ) ,
view_mr_path : merge_request && project_merge_request_path ( source_project , merge_request ) ,
2023-04-23 21:23:45 +05:30
behind_compare_path : project_compare_path (
source_project , from : ref , to : source_default_branch , from_project_id : project . id
2023-07-09 08:55:56 +05:30
)
2023-04-23 21:23:45 +05:30
}
end
2019-12-04 20:38:33 +05:30
def remove_fork_project_warning_message ( project )
_ ( " You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure? " ) %
{ project_full_name : project . full_name }
end
2022-01-26 12:08:38 +05:30
def remove_fork_project_confirm_json ( project , remove_form_id )
{
remove_form_id : remove_form_id ,
button_text : _ ( 'Remove fork relationship' ) ,
confirm_danger_message : remove_fork_project_warning_message ( project ) ,
phrase : @project . path
}
end
2019-12-04 20:38:33 +05:30
def visible_fork_source ( project )
project . fork_source if project . fork_source && can? ( current_user , :read_project , project . fork_source )
end
2017-09-10 17:25:29 +05:30
def project_search_tabs? ( tab )
2023-03-04 22:38:38 +05:30
return false unless @project . present?
2017-09-10 17:25:29 +05:30
abilities = Array ( search_tab_ability_map [ tab ] )
abilities . any? { | ability | can? ( current_user , ability , @project ) }
end
2015-09-11 14:41:01 +05:30
def can_change_visibility_level? ( project , current_user )
2021-03-08 18:12:59 +05:30
can? ( current_user , :change_visibility_level , project )
2015-09-11 14:41:01 +05:30
end
2019-10-12 21:52:04 +05:30
def can_disable_emails? ( project , current_user )
return false if project . group & . emails_disabled?
2019-12-21 20:55:43 +05:30
can? ( current_user , :set_emails_disabled , project )
2019-10-12 21:52:04 +05:30
end
2016-09-13 17:45:13 +05:30
def last_push_event
2018-03-17 18:26:18 +05:30
current_user & . recent_push ( @project )
2016-09-13 17:45:13 +05:30
end
2017-08-17 22:00:37 +05:30
def link_to_autodeploy_doc
2022-05-07 20:08:51 +05:30
link_to _ ( 'About auto deploy' ) , help_page_path ( 'topics/autodevops/stages.md' , anchor : 'auto-deploy' ) , target : '_blank' , rel : 'noopener'
2017-08-17 22:00:37 +05:30
end
def autodeploy_flash_notice ( branch_name )
2020-10-24 23:57:45 +05:30
html_escape ( _ ( " Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc} " ) ) %
{ branch_name : tag . strong ( truncate ( sanitize ( branch_name ) ) ) , link_to_autodeploy_doc : link_to_autodeploy_doc }
2017-08-17 22:00:37 +05:30
end
2019-07-07 11:18:12 +05:30
def project_list_cache_key ( project , pipeline_status : true )
2017-09-10 17:25:29 +05:30
key = [
2022-10-11 01:57:18 +05:30
project . star_count ,
2017-09-10 17:25:29 +05:30
project . route . cache_key ,
project . cache_key ,
2018-11-08 19:23:39 +05:30
project . last_activity_date ,
2017-09-10 17:25:29 +05:30
controller . controller_name ,
controller . action_name ,
2018-03-17 18:26:18 +05:30
Gitlab :: CurrentSettings . cache_key ,
2018-03-27 19:54:05 +05:30
" cross-project: #{ can? ( current_user , :read_cross_project ) } " ,
2018-11-08 19:23:39 +05:30
max_project_member_access_cache_key ( project ) ,
2019-07-07 11:18:12 +05:30
pipeline_status ,
2020-01-01 13:55:28 +05:30
Gitlab :: I18n . locale ,
2018-11-08 19:23:39 +05:30
'v2.6'
2017-09-10 17:25:29 +05:30
]
2019-07-07 11:18:12 +05:30
key << pipeline_status_cache_key ( project . pipeline_status ) if pipeline_status && project . pipeline_status . has_status?
2017-08-17 22:00:37 +05:30
key
end
def load_pipeline_status ( projects )
2017-09-10 17:25:29 +05:30
Gitlab :: Cache :: Ci :: ProjectPipelineStatus
. load_in_batch_for_projects ( projects )
end
2023-07-09 08:55:56 +05:30
def last_pipeline_from_status_cache ( project )
if Feature . enabled? ( :last_pipeline_from_pipeline_status , project )
pipeline_status = project . pipeline_status
return unless pipeline_status . has_status?
# commits have far more attributes than id, but last_pipeline only requires sha
return Commit . from_hash ( { id : pipeline_status . sha } , project ) . last_pipeline
end
project . last_pipeline
end
2017-09-10 17:25:29 +05:30
def show_no_ssh_key_message?
2018-11-20 20:47:30 +05:30
Gitlab :: CurrentSettings . user_show_add_ssh_key_message? &&
cookies [ :hide_no_ssh_message ] . blank? &&
! current_user . hide_no_ssh_key &&
current_user . require_ssh_key?
2017-09-10 17:25:29 +05:30
end
def show_no_password_message?
cookies [ :hide_no_password_message ] . blank? && ! current_user . hide_no_password &&
2018-03-17 18:26:18 +05:30
current_user . require_extra_setup_for_git_auth?
2017-09-10 17:25:29 +05:30
end
2019-02-15 15:39:39 +05:30
def show_auto_devops_implicitly_enabled_banner? ( project , user )
return false unless user_can_see_auto_devops_implicitly_enabled_banner? ( project , user )
2018-11-20 20:47:30 +05:30
2019-02-15 15:39:39 +05:30
cookies [ " hide_auto_devops_implicitly_enabled_banner_ #{ project . id } " . to_sym ] . blank?
2018-11-20 20:47:30 +05:30
end
2023-07-09 08:55:56 +05:30
def show_mobile_devops_project_promo? ( project )
return false unless :: Feature . enabled? ( :mobile_devops_projects_promo , project )
return false unless ( project . project_setting . target_platforms & :: ProjectSetting :: ALLOWED_TARGET_PLATFORMS ) . any?
cookies [ " hide_mobile_devops_promo_ #{ project . id } " . to_sym ] . blank?
end
2021-12-11 22:18:48 +05:30
def no_password_message
2022-07-16 23:28:13 +05:30
push_pull_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">' . html_safe % { url : help_page_path ( 'topics/git/terminology' , anchor : 'pull-and-push' ) }
2021-12-11 22:18:48 +05:30
clone_with_https_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">' . html_safe % { url : help_page_path ( 'gitlab-basics/start-using-git' , anchor : 'clone-with-https' ) }
set_password_link_start = '<a href="%{url}">' . html_safe % { url : edit_profile_password_path }
set_up_pat_link_start = '<a href="%{url}">' . html_safe % { url : profile_personal_access_tokens_path }
message = if current_user . require_password_creation_for_git?
_ ( 'Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_password_link_start}set a password%{link_end} or %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}.' )
else
_ ( 'Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}.' )
end
html_escape ( message ) % {
push_pull_link_start : push_pull_link_start ,
protocol : gitlab_config . protocol . upcase ,
clone_with_https_link_start : clone_with_https_link_start ,
set_password_link_start : set_password_link_start ,
set_up_pat_link_start : set_up_pat_link_start ,
link_end : '</a>' . html_safe
}
2017-09-10 17:25:29 +05:30
end
# Returns true if any projects are present.
#
# If the relation has a LIMIT applied we'll cast the relation to an Array
# since repeated any? checks would otherwise result in multiple COUNT queries
# being executed.
#
# If no limit is applied we'll just issue a COUNT since the result set could
# be too large to load into memory.
def any_projects? ( projects )
return projects . any? if projects . is_a? ( Array )
if projects . limit_value
projects . to_a . any?
else
projects . except ( :offset ) . any?
end
end
2018-03-17 18:26:18 +05:30
def show_projects? ( projects , params )
2023-03-04 22:38:38 +05:30
! ! ( params [ :personal ] || params [ :name ] || params [ :language ] || any_projects? ( projects ) )
2017-08-17 22:00:37 +05:30
end
2018-03-27 19:54:05 +05:30
def push_to_create_project_command ( user = current_user )
repository_url =
if Gitlab :: CurrentSettings . current_application_settings . enabled_git_access_protocol == 'http'
user_url ( user )
else
Gitlab . config . gitlab_shell . ssh_path_prefix + user . username
end
" git push --set-upstream #{ repository_url } /$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD) "
end
2018-11-08 19:23:39 +05:30
def show_xcode_link? ( project = @project )
browser . platform . mac? && project . repository . xcode_project?
end
def xcode_uri_to_repo ( project = @project )
" xcode://clone?repo= #{ CGI . escape ( default_url_to_repo ( project ) ) } "
end
2019-02-15 15:39:39 +05:30
def explore_projects_tab?
current_page? ( explore_projects_path ) ||
current_page? ( trending_explore_projects_path ) ||
current_page? ( starred_explore_projects_path )
end
2023-04-23 21:23:45 +05:30
def show_count? ( disabled : false , compact_mode : false )
2020-05-24 23:13:21 +05:30
! disabled && ! compact_mode
2019-02-15 15:39:39 +05:30
end
2019-07-07 11:18:12 +05:30
def error_tracking_setting_project_json
setting = @project . error_tracking_setting
return if setting . blank? || setting . project_slug . blank? ||
setting . organization_slug . blank?
{
2022-07-01 11:34:44 +05:30
sentry_project_id : setting . sentry_project_id ,
2019-07-07 11:18:12 +05:30
name : setting . project_name ,
organization_name : setting . organization_name ,
organization_slug : setting . organization_slug ,
slug : setting . project_slug
} . to_json
end
2019-07-31 22:56:46 +05:30
def directory?
@path . present?
end
2019-07-07 11:18:12 +05:30
def external_classification_label_help_message
default_label = :: Gitlab :: CurrentSettings . current_application_settings
. external_authorization_service_default_label
s_ (
" ExternalAuthorizationService|When no classification label is set the " \
" default label `%{default_label}` will be used. "
) % { default_label : default_label }
end
2021-10-27 15:23:28 +05:30
def can_admin_project_member? ( project )
Ability . allowed? ( current_user , :admin_project_member , project ) && ! membership_locked?
2019-09-04 21:01:54 +05:30
end
def project_can_be_shared?
! membership_locked? || @project . allowed_to_share_with_group?
end
def membership_locked?
false
end
def metrics_external_dashboard_url
@project . metrics_setting_external_dashboard_url
end
2020-06-23 00:09:42 +05:30
def metrics_dashboard_timezone
@project . metrics_setting_dashboard_timezone
end
2019-12-21 20:55:43 +05:30
def grafana_integration_url
@project . grafana_integration & . grafana_url
end
2020-02-01 01:16:34 +05:30
def grafana_integration_masked_token
@project . grafana_integration & . masked_token
2019-12-21 20:55:43 +05:30
end
2019-12-26 22:10:19 +05:30
def grafana_integration_enabled?
@project . grafana_integration & . enabled?
end
2020-04-08 14:13:33 +05:30
def project_license_name ( project )
2020-07-28 23:09:34 +05:30
key = " project: #{ project . id } :license_name "
Gitlab :: SafeRequestStore . fetch ( key ) { project . repository . license & . name }
2020-04-08 14:13:33 +05:30
rescue GRPC :: Unavailable , GRPC :: DeadlineExceeded , Gitlab :: Git :: CommandError = > e
Gitlab :: ErrorTracking . track_exception ( e )
2020-07-28 23:09:34 +05:30
Gitlab :: SafeRequestStore [ key ] = nil
2020-04-08 14:13:33 +05:30
nil
end
2021-09-30 23:02:18 +05:30
def show_terraform_banner? ( project )
2022-07-16 23:28:13 +05:30
Feature . enabled? ( :show_terraform_banner , type : :ops ) && project . repository_languages . with_programming_language ( 'HCL' ) . exists? && project . terraform_states . empty?
2021-09-30 23:02:18 +05:30
end
2021-10-27 15:23:28 +05:30
def project_permissions_panel_data ( project )
{
packagesAvailable : :: Gitlab . config . packages . enabled ,
packagesHelpPath : help_page_path ( 'user/packages/index' ) ,
currentSettings : project_permissions_settings ( project ) ,
canDisableEmails : can_disable_emails? ( project , current_user ) ,
canChangeVisibilityLevel : can_change_visibility_level? ( project , current_user ) ,
allowedVisibilityOptions : project_allowed_visibility_levels ( project ) ,
2022-08-13 15:12:31 +05:30
visibilityHelpPath : help_page_path ( 'user/public_access' ) ,
2021-10-27 15:23:28 +05:30
registryAvailable : Gitlab . config . registry . enabled ,
registryHelpPath : help_page_path ( 'user/packages/container_registry/index' ) ,
lfsAvailable : Gitlab . config . lfs . enabled ,
lfsHelpPath : help_page_path ( 'topics/git/lfs/index' ) ,
lfsObjectsExist : project . lfs_objects . exists? ,
lfsObjectsRemovalHelpPath : help_page_path ( 'topics/git/lfs/index' , anchor : 'removing-objects-from-lfs' ) ,
pagesAvailable : Gitlab . config . pages . enabled ,
pagesAccessControlEnabled : Gitlab . config . pages . access_control ,
pagesAccessControlForced : :: Gitlab :: Pages . access_control_is_forced? ,
pagesHelpPath : help_page_path ( 'user/project/pages/introduction' , anchor : 'gitlab-pages-access-control' ) ,
2022-08-13 15:12:31 +05:30
issuesHelpPath : help_page_path ( 'user/project/issues/index' ) ,
2022-10-11 01:57:18 +05:30
membersPagePath : project_project_members_path ( project ) ,
environmentsHelpPath : help_page_path ( 'ci/environments/index' ) ,
featureFlagsHelpPath : help_page_path ( 'operations/feature_flags' ) ,
2023-01-13 00:05:48 +05:30
releasesHelpPath : help_page_path ( 'user/project/releases/index' ) ,
infrastructureHelpPath : help_page_path ( 'user/infrastructure/index' )
2021-10-27 15:23:28 +05:30
}
end
2021-10-29 20:43:33 +05:30
def project_classes ( project )
return " project-highlight-puc " if project . warn_about_potentially_unwanted_characters?
" "
end
2021-12-11 22:18:48 +05:30
# Returns the confirm phrase the user needs to type in order to delete the project
#
# Thus the phrase should include the namespace to make it very clear to the
# user which project is subject to deletion.
# Relevant issue: https://gitlab.com/gitlab-org/gitlab/-/issues/343591
def delete_confirm_phrase ( project )
project . path_with_namespace
end
2022-06-21 17:19:12 +05:30
def able_to_see_issues? ( project , user )
project . issues_enabled? && can? ( user , :read_issue , project )
end
def able_to_see_merge_requests? ( project , user )
project . merge_requests_enabled? && can? ( user , :read_merge_request , project )
end
2023-04-23 21:23:45 +05:30
def able_to_see_forks_count? ( project , user )
project . forking_enabled? && can? ( user , :read_code , project )
end
2022-01-26 12:08:38 +05:30
def fork_button_disabled_tooltip ( project )
return unless current_user
if ! current_user . can? ( :fork_project , project )
s_ ( " ProjectOverview|You don't have permission to fork this project " )
elsif ! current_user . can? ( :create_fork )
s_ ( 'ProjectOverview|You have reached your project limit' )
end
end
2022-04-04 11:22:00 +05:30
def import_from_bitbucket_message
2022-05-07 20:08:51 +05:30
configure_oauth_import_message ( 'Bitbucket' , help_page_path ( " integration/bitbucket " ) )
end
def import_from_gitlab_message
configure_oauth_import_message ( 'GitLab.com' , help_page_path ( " integration/gitlab " ) )
end
2022-04-04 11:22:00 +05:30
2022-07-23 23:45:48 +05:30
def show_inactive_project_deletion_banner? ( project )
return false unless project . present? && project . saved?
return false unless delete_inactive_projects?
project . inactive?
end
def inactive_project_deletion_date ( project )
Gitlab :: InactiveProjectsDeletionWarningTracker . new ( project . id ) . scheduled_deletion_date
end
def show_clusters_alert? ( project )
Gitlab . com? && can_admin_associated_clusters? ( project )
end
def clusters_deprecation_alert_message
if has_active_license?
2023-05-27 22:25:52 +05:30
s_ ( 'ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions.' )
2022-07-23 23:45:48 +05:30
else
2022-10-11 01:57:18 +05:30
s_ ( 'ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}.' )
2022-07-23 23:45:48 +05:30
end
end
2022-08-27 11:52:29 +05:30
def project_coverage_chart_data_attributes ( daily_coverage_options , ref )
{
graph_endpoint : " #{ daily_coverage_options [ :graph_api_path ] } ? #{ daily_coverage_options [ :base_params ] . to_query } " ,
2023-03-04 22:38:38 +05:30
graph_start_date : daily_coverage_options [ :base_params ] [ :start_date ] . strftime ( '%b %d' ) ,
graph_end_date : daily_coverage_options [ :base_params ] [ :end_date ] . strftime ( '%b %d' ) ,
graph_ref : ref . to_s ,
2022-08-27 11:52:29 +05:30
graph_csv_path : " #{ daily_coverage_options [ :download_path ] } ? #{ daily_coverage_options [ :base_params ] . to_query } "
}
end
2022-11-25 23:54:43 +05:30
def localized_project_human_access ( access )
localized_access_names [ access ] || Gitlab :: Access . human_access ( access )
end
2023-01-13 00:05:48 +05:30
def badge_count ( number )
format_cached_count ( 1000 , number )
end
2023-05-27 22:25:52 +05:30
def remote_mirror_setting_enabled?
false
end
def http_clone_url_to_repo ( project )
project . http_url_to_repo
end
def ssh_clone_url_to_repo ( project )
project . ssh_url_to_repo
end
2022-05-07 20:08:51 +05:30
private
2023-07-09 08:55:56 +05:30
def create_merge_request_path ( project , source_project , ref , merge_request )
return if merge_request . present?
return unless can? ( current_user , :create_merge_request_from , project )
return unless can? ( current_user , :create_merge_request_in , source_project )
create_mr_path (
from : ref ,
source_project : project ,
to : source_project . default_branch ,
target_project : source_project )
end
def can_sync_branch? ( project , ref )
return false unless project . repository . branch_exists? ( ref )
:: Gitlab :: UserAccess . new ( current_user , container : project ) . can_push_to_branch? ( ref )
end
2022-11-25 23:54:43 +05:30
def localized_access_names
{
Gitlab :: Access :: NO_ACCESS = > _ ( 'No access' ) ,
Gitlab :: Access :: MINIMAL_ACCESS = > _ ( " Minimal Access " ) ,
Gitlab :: Access :: GUEST = > _ ( 'Guest' ) ,
Gitlab :: Access :: REPORTER = > _ ( 'Reporter' ) ,
Gitlab :: Access :: DEVELOPER = > _ ( 'Developer' ) ,
Gitlab :: Access :: MAINTAINER = > _ ( 'Maintainer' ) ,
Gitlab :: Access :: OWNER = > _ ( 'Owner' )
}
end
2022-05-07 20:08:51 +05:30
def configure_oauth_import_message ( provider , help_url )
2023-03-17 16:20:25 +05:30
str = if current_user . can_admin_all_resources?
2022-05-07 20:08:51 +05:30
'ImportProjects|To enable importing projects from %{provider}, as administrator you need to configure %{link_start}OAuth integration%{link_end}'
2022-04-04 11:22:00 +05:30
else
2022-05-07 20:08:51 +05:30
'ImportProjects|To enable importing projects from %{provider}, ask your GitLab administrator to configure %{link_start}OAuth integration%{link_end}'
2022-04-04 11:22:00 +05:30
end
2022-05-07 20:08:51 +05:30
link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">' . html_safe % { url : help_url }
s_ ( str ) . html_safe % { provider : provider , link_start : link_start , link_end : '</a>' . html_safe }
2022-04-04 11:22:00 +05:30
end
2017-09-10 17:25:29 +05:30
def tab_ability_map
{
2022-08-27 11:52:29 +05:30
cycle_analytics : :read_cycle_analytics ,
environments : :read_environment ,
2020-06-23 00:09:42 +05:30
metrics_dashboards : :metrics_dashboard ,
2022-08-27 11:52:29 +05:30
milestones : :read_milestone ,
snippets : :read_snippet ,
settings : :admin_project ,
builds : :read_build ,
clusters : :read_cluster ,
serverless : :read_cluster ,
terraform : :read_terraform_state ,
error_tracking : :read_sentry_issue ,
alert_management : :read_alert_management_alert ,
incidents : :read_issue ,
labels : :read_label ,
issues : :read_issue ,
project_members : :read_project_member ,
wiki : :read_wiki ,
feature_flags : :read_feature_flag ,
analytics : :read_analytics
2017-09-10 17:25:29 +05:30
}
end
def search_tab_ability_map
@search_tab_ability_map || = tab_ability_map . merge (
2023-03-04 22:38:38 +05:30
blobs : :read_code ,
commits : :read_code ,
2017-09-10 17:25:29 +05:30
merge_requests : :read_merge_request ,
2023-03-04 22:38:38 +05:30
notes : [ :read_merge_request , :read_code , :read_issue , :read_snippet ] ,
2022-08-27 11:52:29 +05:30
members : :read_project_member
2017-09-10 17:25:29 +05:30
)
end
2016-09-29 09:46:39 +05:30
def project_lfs_status ( project )
if project . lfs_enabled?
content_tag ( :span , class : 'lfs-enabled' ) do
2017-09-10 17:25:29 +05:30
s_ ( 'LFSStatus|Enabled' )
2016-09-29 09:46:39 +05:30
end
else
content_tag ( :span , class : 'lfs-disabled' ) do
2017-09-10 17:25:29 +05:30
s_ ( 'LFSStatus|Disabled' )
2016-09-29 09:46:39 +05:30
end
end
end
2014-09-02 18:07:02 +05:30
def git_user_name
if current_user
2018-03-17 18:26:18 +05:30
current_user . name . gsub ( '"' , '\"' )
2014-09-02 18:07:02 +05:30
else
2017-09-10 17:25:29 +05:30
_ ( " Your name " )
2014-09-02 18:07:02 +05:30
end
end
def git_user_email
if current_user
2021-11-11 11:23:49 +05:30
current_user . commit_email_or_default
2014-09-02 18:07:02 +05:30
else
" your@email.com "
end
end
2015-12-23 02:04:40 +05:30
def default_url_to_repo ( project = @project )
2016-06-02 11:05:42 +05:30
case default_clone_protocol
when 'ssh'
2015-12-23 02:04:40 +05:30
project . ssh_url_to_repo
else
2017-09-10 17:25:29 +05:30
project . http_url_to_repo
2015-12-23 02:04:40 +05:30
end
2014-09-02 18:07:02 +05:30
end
2018-11-20 20:47:30 +05:30
def default_clone_label
_ ( " Copy %{protocol} clone URL " ) % { protocol : default_clone_protocol . upcase }
end
2014-09-02 18:07:02 +05:30
def default_clone_protocol
2016-08-24 12:49:21 +05:30
if allowed_protocols_present?
enabled_protocol
2015-12-23 02:04:40 +05:30
else
2018-11-08 19:23:39 +05:30
extra_default_clone_protocol
end
end
def extra_default_clone_protocol
if ! current_user || current_user . require_ssh_key?
gitlab_config . protocol
else
'ssh'
2015-12-23 02:04:40 +05:30
end
2014-09-02 18:07:02 +05:30
end
def project_last_activity ( project )
if project . last_activity_at
2015-09-11 14:41:01 +05:30
time_ago_with_tooltip ( project . last_activity_at , placement : 'bottom' , html_class : 'last_activity_time_ago' )
2014-09-02 18:07:02 +05:30
else
2017-09-10 17:25:29 +05:30
s_ ( " ProjectLastActivity|Never " )
2014-09-02 18:07:02 +05:30
end
end
2015-04-26 12:48:37 +05:30
def project_status_css_class ( status )
case status
when " started "
2018-11-08 19:23:39 +05:30
" table-active "
2015-04-26 12:48:37 +05:30
when " failed "
2018-11-08 19:23:39 +05:30
" table-danger "
2015-04-26 12:48:37 +05:30
when " finished "
2018-11-08 19:23:39 +05:30
" table-success "
2015-04-26 12:48:37 +05:30
end
end
2015-09-11 14:41:01 +05:30
def readme_cache_key
sha = @project . commit . try ( :sha ) || 'nil'
2017-09-10 17:25:29 +05:30
[ @project . full_path , sha , " readme " ] . join ( '-' )
2015-09-11 14:41:01 +05:30
end
2015-09-25 12:07:36 +05:30
def current_ref
@ref || @repository . try ( :root_ref )
end
2016-11-03 12:29:30 +05:30
def project_child_container_class ( view_path )
2020-07-28 23:09:34 +05:30
view_path == " projects/issues/issues " ? " gl-mt-3 " : " project-show- #{ view_path } "
2016-11-03 12:29:30 +05:30
end
2017-08-17 22:00:37 +05:30
def project_issues ( project )
IssuesFinder . new ( current_user , project_id : project . id ) . execute
end
def restricted_levels
2023-03-17 16:20:25 +05:30
return [ ] if current_user . can_admin_all_resources?
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
Gitlab :: CurrentSettings . restricted_visibility_levels || [ ]
end
def project_permissions_settings ( project )
feature = project . project_feature
{
2020-10-24 23:57:45 +05:30
packagesEnabled : ! ! project . packages_enabled ,
2022-07-23 23:45:48 +05:30
packageRegistryAccessLevel : feature . package_registry_access_level ,
2018-03-17 18:26:18 +05:30
visibilityLevel : project . visibility_level ,
requestAccessEnabled : ! ! project . request_access_enabled ,
issuesAccessLevel : feature . issues_access_level ,
repositoryAccessLevel : feature . repository_access_level ,
2020-03-13 15:44:24 +05:30
forkingAccessLevel : feature . forking_access_level ,
2018-03-17 18:26:18 +05:30
mergeRequestsAccessLevel : feature . merge_requests_access_level ,
buildsAccessLevel : feature . builds_access_level ,
wikiAccessLevel : feature . wiki_access_level ,
snippetsAccessLevel : feature . snippets_access_level ,
2018-12-05 23:21:45 +05:30
pagesAccessLevel : feature . pages_access_level ,
2021-02-22 17:27:13 +05:30
analyticsAccessLevel : feature . analytics_access_level ,
2018-03-17 18:26:18 +05:30
containerRegistryEnabled : ! ! project . container_registry_enabled ,
2019-10-12 21:52:04 +05:30
lfsEnabled : ! ! project . lfs_enabled ,
2020-05-24 23:13:21 +05:30
emailsDisabled : project . emails_disabled? ,
metricsDashboardAccessLevel : feature . metrics_dashboard_access_level ,
2022-10-11 01:57:18 +05:30
monitorAccessLevel : feature . monitor_access_level ,
2021-02-22 17:27:13 +05:30
showDefaultAwardEmojis : project . show_default_award_emojis? ,
2021-10-29 20:43:33 +05:30
warnAboutPotentiallyUnwantedCharacters : project . warn_about_potentially_unwanted_characters? ,
2022-07-16 23:28:13 +05:30
enforceAuthChecksOnUploads : project . enforce_auth_checks_on_uploads? ,
2021-10-27 15:23:28 +05:30
securityAndComplianceAccessLevel : project . security_and_compliance_access_level ,
2022-08-27 11:52:29 +05:30
containerRegistryAccessLevel : feature . container_registry_access_level ,
environmentsAccessLevel : feature . environments_access_level ,
featureFlagsAccessLevel : feature . feature_flags_access_level ,
2023-01-13 00:05:48 +05:30
releasesAccessLevel : feature . releases_access_level ,
infrastructureAccessLevel : feature . infrastructure_access_level
2018-03-17 18:26:18 +05:30
}
end
def project_allowed_visibility_levels ( project )
Gitlab :: VisibilityLevel . values . select do | level |
project . visibility_level_allowed? ( level ) && ! restricted_levels . include? ( level )
end
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
def find_file_path
return unless @project && ! @project . empty_repo?
2023-03-04 22:38:38 +05:30
return unless can? ( current_user , :read_code , @project )
2017-09-10 17:25:29 +05:30
ref = @ref || @project . repository . root_ref
project_find_file_path ( @project , ref )
end
2018-03-27 19:54:05 +05:30
def can_show_last_commit_in_list? ( project )
2022-06-21 17:19:12 +05:30
can? ( current_user , :read_cross_project ) &&
can? ( current_user , :read_commit_status , project ) &&
project . commit
2018-03-27 19:54:05 +05:30
end
2018-05-09 12:01:36 +05:30
def pages_https_only_disabled?
! @project . pages_domains . all? ( & :https? )
end
def pages_https_only_title
return unless pages_https_only_disabled?
" You must enable HTTPS for all your domains first "
end
2019-10-12 21:52:04 +05:30
def filter_starrer_path ( options = { } )
options = params . slice ( :sort ) . merge ( options ) . permit!
" #{ request . path } ? #{ options . to_param } "
end
2018-12-13 13:39:08 +05:30
def sidebar_operations_paths
%w[
environments
clusters
2021-12-11 22:18:48 +05:30
cluster_agents
2019-02-15 15:39:39 +05:30
functions
error_tracking
2020-05-24 23:13:21 +05:30
alert_management
2020-10-24 23:57:45 +05:30
incidents
incident_management
2018-12-13 13:39:08 +05:30
user
gcp
2020-01-01 13:55:28 +05:30
logs
2020-10-24 23:57:45 +05:30
product_analytics
metrics_dashboard
2021-01-03 14:25:43 +05:30
feature_flags
2021-01-29 00:20:46 +05:30
terraform
2018-12-13 13:39:08 +05:30
]
end
2019-02-15 15:39:39 +05:30
def user_can_see_auto_devops_implicitly_enabled_banner? ( project , user )
Ability . allowed? ( user , :admin_project , project ) &&
project . has_auto_devops_implicitly_enabled? &&
project . builds_enabled? &&
! project . repository . gitlab_ci_yml
end
2019-09-04 21:01:54 +05:30
2020-01-01 13:55:28 +05:30
def show_visibility_confirm_modal? ( project )
2023-05-27 22:25:52 +05:30
project . visibility_level > Gitlab :: VisibilityLevel :: PRIVATE && project . forks_count > 0
2020-01-01 13:55:28 +05:30
end
2020-03-13 15:44:24 +05:30
2022-03-02 08:16:31 +05:30
def confirm_reduce_visibility_message ( project )
strong_start = " <strong> " . html_safe
strong_end = " </strong> " . html_safe
message = _ ( " You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end}. " )
if project . group
message = _ ( " You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end} in %{strong_start}%{group_name}%{strong_end}. " )
end
html_escape ( message ) % { strong_start : strong_start , strong_end : strong_end , project_name : project . name , group_name : project . group ? project . group . name : nil }
end
def visibility_confirm_modal_data ( project , target_form_id = nil )
{
target_form_id : target_form_id ,
button_testid : 'reduce-project-visibility-button' ,
confirm_button_text : _ ( 'Reduce project visibility' ) ,
confirm_danger_message : confirm_reduce_visibility_message ( project ) ,
phrase : project . full_path ,
additional_information : _ ( 'Note: current forks will keep their visibility level.' ) ,
html_confirmation_message : true . to_s ,
show_visibility_confirm_modal : show_visibility_confirm_modal? ( project ) . to_s
}
end
2021-01-29 00:20:46 +05:30
def build_project_breadcrumb_link ( project )
project_name = simple_sanitize ( project . name )
push_to_schema_breadcrumb ( project_name , project_path ( project ) )
link_to project_path ( project ) do
icon = project_icon ( project , alt : project_name , class : 'avatar-tile' , width : 15 , height : 15 ) if project . avatar_url && ! Rails . env . test?
[ icon , content_tag ( " span " , project_name , class : " breadcrumb-item-text js-breadcrumb-item-text " ) ] . join . html_safe
end
end
def build_namespace_breadcrumb_link ( project )
if project . group
group_title ( project . group , nil , nil )
else
owner = project . namespace . owner
name = simple_sanitize ( owner . name )
url = user_path ( owner )
push_to_schema_breadcrumb ( name , url )
link_to ( name , url )
end
end
2022-07-23 23:45:48 +05:30
def delete_inactive_projects?
strong_memoize ( :delete_inactive_projects_setting ) do
:: Gitlab :: CurrentSettings . delete_inactive_projects?
end
end
end
def can_admin_associated_clusters? ( project )
can_admin_project_clusters? ( project ) || can_admin_group_clusters? ( project )
end
def can_admin_project_clusters? ( project )
project . clusters . any? && can? ( current_user , :admin_cluster , project )
end
def can_admin_group_clusters? ( project )
project . group && project . group . clusters . any? && can? ( current_user , :admin_cluster , project . group )
2014-09-02 18:07:02 +05:30
end
2020-04-22 19:07:51 +05:30
2023-06-20 00:43:36 +05:30
def can_view_branch_rules?
can? ( current_user , :maintainer_access , @project )
end
def branch_rules_path
project_settings_repository_path ( @project , anchor : 'js-branch-rules' )
end
2021-06-08 01:23:25 +05:30
ProjectsHelper . prepend_mod_with ( 'ProjectsHelper' )