summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/branches_helper.rb6
-rw-r--r--app/helpers/preferences_helper.rb26
-rw-r--r--app/helpers/projects_helper.rb307
-rw-r--r--app/helpers/tree_helper.rb2
-rw-r--r--app/models/project.rb7
-rw-r--r--app/presenters/project_presenter.rb359
-rw-r--r--app/views/projects/_readme.html.haml2
-rw-r--r--app/views/projects/buttons/_koding.html.haml2
-rw-r--r--app/views/projects/empty.html.haml5
-rw-r--r--app/views/projects/show.html.haml8
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--spec/features/projects/show_project_spec.rb12
-rw-r--r--spec/helpers/projects_helper_spec.rb26
-rw-r--r--spec/presenters/project_presenter_spec.rb31
15 files changed, 416 insertions, 381 deletions
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 6530327698b..479797231cc 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -34,7 +34,7 @@ module ApplicationHelper
def project_icon(project_id, options = {})
project =
- if project_id.is_a?(Project)
+ if project_id.is_a?(Project) || project_id.is_a?(ProjectPresenter)
project_id
else
Project.find_by_full_path(project_id)
diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb
index 2641a98e29e..00b9a0e00eb 100644
--- a/app/helpers/branches_helper.rb
+++ b/app/helpers/branches_helper.rb
@@ -10,12 +10,6 @@ module BranchesHelper
project_branches_path(@project, @id, options)
end
- def can_push_branch?(project, branch_name)
- return false unless project.repository.branch_exists?(branch_name)
-
- ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(branch_name)
- end
-
def project_branches
options_for_select(@project.repository.branch_names, @project.default_branch)
end
diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb
index aaee6eaeedd..373dfd457f7 100644
--- a/app/helpers/preferences_helper.rb
+++ b/app/helpers/preferences_helper.rb
@@ -48,30 +48,4 @@ module PreferencesHelper
def user_color_scheme
Gitlab::ColorSchemes.for_user(current_user).css_class
end
-
- def default_project_view
- return anonymous_project_view unless current_user
-
- user_view = current_user.project_view
-
- if can?(current_user, :download_code, @project)
- user_view
- elsif user_view == "activity"
- "activity"
- elsif can?(current_user, :read_wiki, @project)
- "wiki"
- elsif @project.feature_available?(:issues, current_user)
- "projects/issues/issues"
- else
- "customize_workflow"
- end
- end
-
- def anonymous_project_view
- if !@project.empty_repo? && can?(current_user, :download_code, @project)
- 'files'
- else
- 'activity'
- end
- end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 0c64b8abec3..fa6811dccbf 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -153,11 +153,6 @@ module ProjectsHelper
end
end
- def license_short_name(project)
- license = project.repository.license
- license&.nickname || license&.name || 'LICENSE'
- end
-
def last_push_event
current_user&.recent_push(@project)
end
@@ -386,55 +381,6 @@ module ProjectsHelper
end
end
- def add_special_file_path(project, file_name:, commit_message: nil, branch_name: nil, context: nil)
- commit_message ||= s_("CommitMessage|Add %{file_name}") % { file_name: file_name }
- project_new_blob_path(
- project,
- project.default_branch || 'master',
- file_name: file_name,
- commit_message: commit_message,
- branch_name: branch_name,
- context: context
- )
- end
-
- def add_koding_stack_path(project)
- project_new_blob_path(
- project,
- project.default_branch || 'master',
- file_name: '.koding.yml',
- commit_message: "Add Koding stack script",
- content: <<-CONTENT.strip_heredoc
- provider:
- aws:
- access_key: '${var.aws_access_key}'
- secret_key: '${var.aws_secret_key}'
- resource:
- aws_instance:
- #{project.path}-vm:
- instance_type: t2.nano
- user_data: |-
-
- # Created by GitLab UI for :>
-
- echo _KD_NOTIFY_@Installing Base packages...@
-
- apt-get update -y
- apt-get install git -y
-
- echo _KD_NOTIFY_@Cloning #{project.name}...@
-
- export KODING_USER=${var.koding_user_username}
- export REPO_URL=#{root_url}${var.koding_queryString_repo}.git
- export BRANCH=${var.koding_queryString_branch}
-
- sudo -i -u $KODING_USER git clone $REPO_URL -b $BRANCH
-
- echo _KD_NOTIFY_@#{project.name} cloned.@
- CONTENT
- )
- end
-
def koding_project_url(project = nil, branch = nil, sha = nil)
if project
import_path = "/Home/Stacks/import"
@@ -451,36 +397,6 @@ module ProjectsHelper
Gitlab::CurrentSettings.koding_url
end
- def contribution_guide_path(project)
- if project && contribution_guide = project.repository.contribution_guide
- project_blob_path(
- project,
- tree_join(project.default_branch,
- contribution_guide.name)
- )
- end
- end
-
- def readme_path(project)
- filename_path(project, :readme)
- end
-
- def changelog_path(project)
- filename_path(project, :changelog)
- end
-
- def license_path(project)
- filename_path(project, :license_blob)
- end
-
- def version_path(project)
- filename_path(project, :version)
- end
-
- def ci_configuration_path(project)
- filename_path(project, :gitlab_ci_yml)
- end
-
def project_wiki_path_with_version(proj, page, version, is_newest)
url_params = is_newest ? {} : { version_id: version }
project_wiki_path(proj, page, url_params)
@@ -506,15 +422,6 @@ module ProjectsHelper
@ref || @repository.try(:root_ref)
end
- def filename_path(project, filename)
- if project && blob = project.repository.public_send(filename) # rubocop:disable GitlabSecurity/PublicSend
- project_blob_path(
- project,
- tree_join(project.default_branch, blob.name)
- )
- end
- end
-
def sanitize_repo_path(project, message)
return '' unless message.present?
@@ -604,218 +511,4 @@ module ProjectsHelper
project_find_file_path(@project, ref)
end
-
- def can_current_user_push_code?(project)
- project.empty_repo? ? can?(current_user, :push_code, project) : can_push_branch?(project, project.default_branch)
- end
-
- def files_anchor_data(project)
- {
- enabled: true,
- label: _('Files (%{human_size})') % { human_size: storage_counter(@project.statistics.total_repository_size) },
- link: project_tree_path(@project)
- }
- end
-
- def commits_anchor_data(project)
- {
- enabled: true,
- label: n_('Commit (%{commit_count})', 'Commits (%{commit_count})', @project.statistics.commit_count) % { commit_count: number_with_delimiter(@project.statistics.commit_count) },
- link: project_commits_path(@project, current_ref)
- }
- end
-
- def branches_anchor_data(project)
- {
- enabled: true,
- label: n_('Branch (%{branch_count})', 'Branches (%{branch_count})', @repository.branch_count) % { branch_count: number_with_delimiter(@repository.branch_count) },
- link: project_branches_path(@project)
- }
- end
-
- def tags_anchor_data(project)
- {
- enabled: true,
- label: n_('Tag (%{tag_count})', 'Tags (%{tag_count})', @repository.tag_count) % { tag_count: number_with_delimiter(@repository.tag_count) },
- link: project_tags_path(@project)
- }
- end
-
- def new_file_anchor_data(project)
- if current_user && can_current_user_push_code?(project)
- {
- enabled: false,
- label: _('New file'),
- link: project_new_blob_path(project, project.default_branch || 'master'),
- class_modifier: 'new'
- }
- end
- end
-
- def readme_anchor_data(project)
- if current_user && can_current_user_push_code?(project) && project.repository.readme.blank?
- {
- enabled: false,
- label: _('Add Readme'),
- link: add_special_file_path(project, file_name: 'README.md')
- }
- elsif project.repository.readme.present?
- {
- enabled: true,
- label: _('Readme'),
- link: default_project_view != 'readme' ? readme_path(@project) : '#readme'
- }
- end
- end
-
- def changelog_anchor_data(project)
- if current_user && can_current_user_push_code?(project) && project.repository.changelog.blank?
- {
- enabled: false,
- label: _('Add Changelog'),
- link: add_special_file_path(project, file_name: 'CHANGELOG')
- }
- elsif project.repository.changelog.present?
- {
- enabled: true,
- label: _('Changelog'),
- link: changelog_path(project)
- }
- end
- end
-
- def license_anchor_data(project)
- if current_user && can_current_user_push_code?(project) && project.repository.license_blob.blank?
- {
- enabled: false,
- label: _('Add License'),
- link: add_special_file_path(project, file_name: 'LICENSE')
- }
- elsif project.repository.license_blob.present?
- {
- enabled: true,
- label: license_short_name(project),
- link: license_path(project)
- }
- end
- end
-
- def contribution_guide_anchor_data(project)
- if current_user && can_current_user_push_code?(project) && project.repository.contribution_guide.blank?
- {
- enabled: false,
- label: _('Add Contribution guide'),
- link: add_special_file_path(project, file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide')
- }
- elsif project.repository.contribution_guide.present?
- {
- enabled: true,
- label: _('Contribution guide'),
- link: contribution_guide_path(@project)
- }
- end
- end
-
- def autodevops_anchor_data(project, ignore_callout: false)
- if current_user && can?(current_user, :admin_pipeline, project) && project.repository.gitlab_ci_yml.blank? && (ignore_callout || !show_auto_devops_callout?(project))
- {
- enabled: project.auto_devops_enabled?,
- label: project.auto_devops_enabled? ? _('Auto DevOps enabled') : _('Enable Auto DevOps'),
- link: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')
- }
- elsif project.auto_devops_enabled?
- {
- enabled: true,
- label: _('Auto DevOps enabled'),
- link: nil
- }
- end
- end
-
- def kubernetes_cluster_anchor_data(project)
- if current_user && can?(current_user, :create_cluster, project)
- cluster_link = project.clusters.size == 1 ? project_cluster_path(project, project.clusters.first) : project_clusters_path(project)
-
- if project.clusters.empty?
- cluster_link = new_project_cluster_path(project)
- end
-
- {
- enabled: !project.clusters.empty?,
- label: project.clusters.empty? ? _('Add Kubernetes cluster') : n_('Kubernetes cluster', 'Kubernetes clusters', project.clusters.size),
- link: cluster_link
- }
- end
- end
-
- def gitlab_ci_anchor_data(project)
- if current_user && can_current_user_push_code?(project) && project.repository.gitlab_ci_yml.blank? && !project.auto_devops_enabled?
- {
- enabled: false,
- label: _('Set up CI/CD'),
- link: add_special_file_path(project, file_name: '.gitlab-ci.yml')
- }
- elsif project.repository.gitlab_ci_yml.present?
- {
- enabled: true,
- label: _('CI/CD configuration'),
- link: ci_configuration_path(@project)
- }
- end
- end
-
- def koding_anchor_data(project)
- if current_user && can_current_user_push_code?(project) && koding_enabled? && project.repository.koding_yml.blank?
- {
- enabled: false,
- label: _('Set up Koding'),
- link: add_koding_stack_path(project)
- }
- end
- end
-
- def empty_project_stat_anchor_items(project)
- [
- autodevops_anchor_data(project, ignore_callout: true),
- kubernetes_cluster_anchor_data(project)
- ].compact.reject { |i| !i[:enabled] }
- end
-
- def empty_project_stat_button_items(project)
- [
- new_file_anchor_data(project),
- readme_anchor_data(project),
- license_anchor_data(project),
- autodevops_anchor_data(project, ignore_callout: true),
- kubernetes_cluster_anchor_data(project)
- ].compact.reject { |i| i[:enabled] }
- end
-
- def project_stat_anchor_items(project)
- [
- files_anchor_data(project),
- commits_anchor_data(project),
- branches_anchor_data(project),
- tags_anchor_data(project),
- readme_anchor_data(project),
- changelog_anchor_data(project),
- license_anchor_data(project),
- contribution_guide_anchor_data(project),
- gitlab_ci_anchor_data(project),
- autodevops_anchor_data(project),
- kubernetes_cluster_anchor_data(project)
- ].compact.reject { |i| !i[:enabled] }
- end
-
- def project_stat_button_items(project)
- [
- changelog_anchor_data(project),
- license_anchor_data(project),
- contribution_guide_anchor_data(project),
- autodevops_anchor_data(project),
- kubernetes_cluster_anchor_data(project),
- gitlab_ci_anchor_data(project),
- koding_anchor_data(project)
- ].compact.reject { |i| i[:enabled] }
- end
end
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index d39cac0f510..0a4da0ef3fc 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -55,7 +55,7 @@ module TreeHelper
def tree_edit_branch(project = @project, ref = @ref)
return unless can_edit_tree?(project, ref)
- if can_push_branch?(project, ref)
+ if project.user_can_push_to_branch?(current_user, ref)
ref
else
project = tree_edit_project(project)
diff --git a/app/models/project.rb b/app/models/project.rb
index 3893b1818f3..03640d7d18b 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -15,6 +15,7 @@ class Project < ActiveRecord::Base
include ValidAttribute
include ProjectFeaturesCompatibility
include SelectForProjectAuthorization
+ include Presentable
include Routable
include GroupDescendant
include Gitlab::SQL::Pattern
@@ -1015,6 +1016,12 @@ class Project < ActiveRecord::Base
!ProtectedBranch.default_branch_protected? || team.max_member_access(user.id) > Gitlab::Access::DEVELOPER
end
+ def user_can_push_to_branch?(user, branch_name)
+ return false unless repository.branch_exists?(branch_name)
+
+ ::Gitlab::UserAccess.new(user, project: self).can_push_to_branch?(branch_name)
+ end
+
def forked?
return true if fork_network && fork_network.root_project != self
diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb
new file mode 100644
index 00000000000..c76a529f56b
--- /dev/null
+++ b/app/presenters/project_presenter.rb
@@ -0,0 +1,359 @@
+class ProjectPresenter < Gitlab::View::Presenter::Delegated
+ include ActionView::Helpers::NumberHelper
+ include ActionView::Helpers::UrlHelper
+ include GitlabRoutingHelper
+ include StorageHelper
+ include TreeHelper
+
+ presents :project
+
+ def project_stat_anchor_items(show_auto_devops_callout:)
+ [
+ files_anchor_data,
+ commits_anchor_data,
+ branches_anchor_data,
+ tags_anchor_data,
+ readme_anchor_data,
+ changelog_anchor_data,
+ license_anchor_data,
+ contribution_guide_anchor_data,
+ gitlab_ci_anchor_data,
+ autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
+ kubernetes_cluster_anchor_data
+ ].compact.reject { |i| !i[:enabled] }
+ end
+
+ def project_stat_button_items(show_auto_devops_callout:)
+ [
+ changelog_anchor_data,
+ license_anchor_data,
+ contribution_guide_anchor_data,
+ autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
+ kubernetes_cluster_anchor_data,
+ gitlab_ci_anchor_data,
+ koding_anchor_data
+ ].compact.reject { |i| i[:enabled] }
+ end
+
+ def empty_project_stat_anchor_items
+ [
+ autodevops_anchor_data,
+ kubernetes_cluster_anchor_data
+ ].compact.reject { |i| !i[:enabled] }
+ end
+
+ def empty_project_stat_button_items
+ [
+ new_file_anchor_data,
+ readme_anchor_data,
+ license_anchor_data,
+ autodevops_anchor_data,
+ kubernetes_cluster_anchor_data
+ ].compact.reject { |i| i[:enabled] }
+ end
+
+ def default_project_view
+ return anonymous_project_view unless current_user
+
+ user_view = current_user.project_view
+
+ if can?(current_user, :download_code, project)
+ user_view
+ elsif user_view == "activity"
+ "activity"
+ elsif can?(current_user, :read_wiki, project)
+ "wiki"
+ elsif feature_available?(:issues, current_user)
+ "projects/issues/issues"
+ else
+ "customize_workflow"
+ end
+ end
+
+ def readme_path
+ filename_path(:readme)
+ end
+
+ def changelog_path
+ filename_path(:changelog)
+ end
+
+ def license_path
+ filename_path(:license_blob)
+ end
+
+ def ci_configuration_path
+ filename_path(:gitlab_ci_yml)
+ end
+
+ def contribution_guide_path
+ if project && contribution_guide = repository.contribution_guide
+ project_blob_path(
+ project,
+ tree_join(project.default_branch,
+ contribution_guide.name)
+ )
+ end
+ end
+
+ def add_license_path
+ add_special_file_path(file_name: 'LICENSE')
+ end
+
+ def add_ci_yml_path
+ add_special_file_path(file_name: '.gitlab-ci.yml')
+ end
+
+ def add_readme_path
+ add_special_file_path(file_name: 'README.md')
+ end
+
+ def add_koding_stack_path
+ project_new_blob_path(
+ project,
+ default_branch || 'master',
+ file_name: '.koding.yml',
+ commit_message: "Add Koding stack script",
+ content: <<-CONTENT.strip_heredoc
+ provider:
+ aws:
+ access_key: '${var.aws_access_key}'
+ secret_key: '${var.aws_secret_key}'
+ resource:
+ aws_instance:
+ #{project.path}-vm:
+ instance_type: t2.nano
+ user_data: |-
+
+ # Created by GitLab UI for :>
+
+ echo _KD_NOTIFY_@Installing Base packages...@
+
+ apt-get update -y
+ apt-get install git -y
+
+ echo _KD_NOTIFY_@Cloning #{project.name}...@
+
+ export KODING_USER=${var.koding_user_username}
+ export REPO_URL=#{root_url}${var.koding_queryString_repo}.git
+ export BRANCH=${var.koding_queryString_branch}
+
+ sudo -i -u $KODING_USER git clone $REPO_URL -b $BRANCH
+
+ echo _KD_NOTIFY_@#{project.name} cloned.@
+ CONTENT
+ )
+ end
+
+ def license_short_name
+ license = repository.license
+ license&.nickname || license&.name || 'LICENSE'
+ end
+
+ private
+
+ def filename_path(filename)
+ if blob = repository.public_send(filename) # rubocop:disable GitlabSecurity/PublicSend
+ project_blob_path(
+ project,
+ tree_join(default_branch, blob.name)
+ )
+ end
+ end
+
+ def anonymous_project_view
+ if !project.empty_repo? && can?(current_user, :download_code, project)
+ 'files'
+ else
+ 'activity'
+ end
+ end
+
+ def add_special_file_path(file_name:, commit_message: nil, branch_name: nil)
+ commit_message ||= s_("CommitMessage|Add %{file_name}") % { file_name: file_name }
+ project_new_blob_path(
+ project,
+ project.default_branch || 'master',
+ file_name: file_name,
+ commit_message: commit_message,
+ branch_name: branch_name
+ )
+ end
+
+ def can_current_user_push_code?
+ if empty_repo?
+ can?(current_user, :push_code, project)
+ else
+ user_can_push_to_branch?(current_user, default_branch)
+ end
+ end
+
+ def files_anchor_data
+ {
+ enabled: true,
+ label: _('Files (%{human_size})') % { human_size: storage_counter(statistics.total_repository_size) },
+ link: project_tree_path(project)
+ }
+ end
+
+ def commits_anchor_data
+ {
+ enabled: true,
+ label: n_('Commit (%{commit_count})', 'Commits (%{commit_count})', statistics.commit_count) % { commit_count: number_with_delimiter(statistics.commit_count) },
+ link: project_commits_path(project, repository.root_ref)
+ }
+ end
+
+ def branches_anchor_data
+ {
+ enabled: true,
+ label: n_('Branch (%{branch_count})', 'Branches (%{branch_count})', repository.branch_count) % { branch_count: number_with_delimiter(repository.branch_count) },
+ link: project_branches_path(project)
+ }
+ end
+
+ def tags_anchor_data
+ {
+ enabled: true,
+ label: n_('Tag (%{tag_count})', 'Tags (%{tag_count})', repository.tag_count) % { tag_count: number_with_delimiter(repository.tag_count) },
+ link: project_tags_path(project)
+ }
+ end
+
+ def new_file_anchor_data
+ if current_user && can_current_user_push_code?
+ {
+ enabled: false,
+ label: _('New file'),
+ link: project_new_blob_path(project, default_branch || 'master'),
+ class_modifier: 'new'
+ }
+ end
+ end
+
+ def readme_anchor_data
+ if current_user && can_current_user_push_code? && repository.readme.blank?
+ {
+ enabled: false,
+ label: _('Add Readme'),
+ link: add_readme_path
+ }
+ elsif repository.readme.present?
+ {
+ enabled: true,
+ label: _('Readme'),
+ link: default_project_view != 'readme' ? readme_path : '#readme'
+ }
+ end
+ end
+
+ def changelog_anchor_data
+ if current_user && can_current_user_push_code? && repository.changelog.blank?
+ {
+ enabled: false,
+ label: _('Add Changelog'),
+ link: add_special_file_path(file_name: 'CHANGELOG')
+ }
+ elsif repository.changelog.present?
+ {
+ enabled: true,
+ label: _('Changelog'),
+ link: changelog_path
+ }
+ end
+ end
+
+ def license_anchor_data
+ if current_user && can_current_user_push_code? && repository.license_blob.blank?
+ {
+ enabled: false,
+ label: _('Add License'),
+ link: add_license_path
+ }
+ elsif repository.license_blob.present?
+ {
+ enabled: true,
+ label: license_short_name,
+ link: license_path
+ }
+ end
+ end
+
+ def contribution_guide_anchor_data
+ if current_user && can_current_user_push_code? && repository.contribution_guide.blank?
+ {
+ enabled: false,
+ label: _('Add Contribution guide'),
+ link: add_special_file_path(file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide')
+ }
+ elsif repository.contribution_guide.present?
+ {
+ enabled: true,
+ label: _('Contribution guide'),
+ link: contribution_guide_path
+ }
+ end
+ end
+
+ def autodevops_anchor_data(show_auto_devops_callout: false)
+ if current_user && can?(current_user, :admin_pipeline, project) && repository.gitlab_ci_yml.blank? && !show_auto_devops_callout
+ {
+ enabled: auto_devops_enabled?,
+ label: auto_devops_enabled? ? _('Auto DevOps enabled') : _('Enable Auto DevOps'),
+ link: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')
+ }
+ elsif auto_devops_enabled?
+ {
+ enabled: true,
+ label: _('Auto DevOps enabled'),
+ link: nil
+ }
+ end
+ end
+
+ def kubernetes_cluster_anchor_data
+ if current_user && can?(current_user, :create_cluster, project)
+ cluster_link = clusters.size == 1 ? project_cluster_path(project, clusters.first) : project_clusters_path(project)
+
+ if clusters.empty?
+ cluster_link = new_project_cluster_path(project)
+ end
+
+ {
+ enabled: !clusters.empty?,
+ label: clusters.empty? ? _('Add Kubernetes cluster') : n_('Kubernetes cluster', 'Kubernetes clusters', clusters.size),
+ link: cluster_link
+ }
+ end
+ end
+
+ def gitlab_ci_anchor_data
+ if current_user && can_current_user_push_code? && repository.gitlab_ci_yml.blank? && !auto_devops_enabled?
+ {
+ enabled: false,
+ label: _('Set up CI/CD'),
+ link: add_ci_yml_path
+ }
+ elsif repository.gitlab_ci_yml.present?
+ {
+ enabled: true,
+ label: _('CI/CD configuration'),
+ link: ci_configuration_path
+ }
+ end
+ end
+
+ def koding_anchor_data
+ if current_user && can_current_user_push_code? && koding_enabled? && repository.koding_yml.blank?
+ {
+ enabled: false,
+ label: _('Set up Koding'),
+ link: add_koding_stack_path
+ }
+ end
+ end
+
+ def koding_enabled?
+ Gitlab::CurrentSettings.koding_enabled?
+ end
+end
diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml
index aebdfbc8218..705338c083e 100644
--- a/app/views/projects/_readme.html.haml
+++ b/app/views/projects/_readme.html.haml
@@ -20,4 +20,4 @@
distributed with computer software, forming part of its documentation.
GitLab will render it here instead of this message.
%p
- = link_to "Add Readme", add_special_file_path(@project, file_name: 'README.md'), class: 'btn btn-new'
+ = link_to "Add Readme", @project.add_readme_path, class: 'btn btn-new'
diff --git a/app/views/projects/buttons/_koding.html.haml b/app/views/projects/buttons/_koding.html.haml
index de2d61d4aa3..b9cec834ab4 100644
--- a/app/views/projects/buttons/_koding.html.haml
+++ b/app/views/projects/buttons/_koding.html.haml
@@ -1,3 +1,3 @@
-- if koding_enabled? && current_user && @repository.koding_yml && can_push_branch?(@project, @project.default_branch)
+- if koding_enabled? && current_user && @repository.koding_yml && @project.user_can_push_to_branch?(current_user, @project.default_branch)
= link_to koding_project_url(@project), class: 'btn project-action-button inline', target: '_blank', rel: 'noopener noreferrer' do
_('Run in IDE (Koding)')
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 01fb9dab313..b4f91f447f9 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -1,5 +1,6 @@
- @no_container = true
- breadcrumb_title "Details"
+- @project = @project.present(current_user: current_user)
= render partial: 'flash_messages', locals: { project: @project }
@@ -32,8 +33,8 @@
.prepend-top-20
%nav.project-stats{ class: container_class }
- = render 'stat_anchor_list', anchors: empty_project_stat_anchor_items(@project)
- = render 'stat_anchor_list', anchors: empty_project_stat_button_items(@project)
+ = render 'stat_anchor_list', anchors: @project.empty_project_stat_anchor_items
+ = render 'stat_anchor_list', anchors: @project.empty_project_stat_button_items
- if can?(current_user, :push_code, @project)
%div{ class: [container_class, ("limit-container-width-sm" unless fluid_layout)] }
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 3d23b19b815..385a3b490a4 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,6 +1,8 @@
+- project_stat_items_args = { show_auto_devops_callout: show_auto_devops_callout?(@project) }
- @no_container = true
- breadcrumb_title "Details"
- @content_class = "limit-container-width" unless fluid_layout
+- @project = @project.present(current_user: current_user)
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_path(@project, rss_url_options), title: "#{@project.name} activity")
@@ -14,8 +16,8 @@
- if can?(current_user, :download_code, @project)
%nav.project-stats{ class: container_class }
- = render 'stat_anchor_list', anchors: project_stat_anchor_items(@project)
- = render 'stat_anchor_list', anchors: project_stat_button_items(@project)
+ = render 'stat_anchor_list', anchors: @project.project_stat_anchor_items(project_stat_items_args)
+ = render 'stat_anchor_list', anchors: @project.project_stat_button_items(project_stat_items_args)
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
@@ -25,7 +27,7 @@
= icon("exclamation-triangle fw")
#{ _('Archived project! Repository is read-only') }
- - view_path = default_project_view
+ - view_path = @project.default_project_view
- if show_auto_devops_callout?(@project)
= render 'shared/auto_devops_callout'
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 79021a08719..6dfabd7ba4c 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -69,7 +69,7 @@
- else
= form.submit 'Save changes', class: 'btn btn-save'
- - if !issuable.persisted? && !issuable.project.empty_repo? && (guide_url = contribution_guide_path(issuable.project))
+ - if !issuable.persisted? && !issuable.project.empty_repo? && (guide_url = issuable.project.present.contribution_guide_path)
.inline.prepend-top-10
Please review the
%strong= link_to('contribution guidelines', guide_url)
diff --git a/spec/features/projects/show_project_spec.rb b/spec/features/projects/show_project_spec.rb
index f5f2bbb49e0..0bd13a17dc9 100644
--- a/spec/features/projects/show_project_spec.rb
+++ b/spec/features/projects/show_project_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe 'Project show page', :feature do
- include ProjectsHelper
-
context 'when project pending delete' do
let(:project) { create(:project, :empty_repo, pending_delete: true) }
@@ -29,6 +27,7 @@ describe 'Project show page', :feature do
describe 'empty project' do
let(:project) { create(:project, :public, :empty_repo) }
+ let(:presenter) { project.present(current_user: user) }
describe 'as a normal user' do
before do
@@ -71,13 +70,13 @@ describe 'Project show page', :feature do
it '"Add Readme" button linked to new file populated for a readme' do
page.within('.project-stats') do
- expect(page).to have_link('Add Readme', href: add_special_file_path(project, file_name: 'README.md'))
+ expect(page).to have_link('Add Readme', href: presenter.add_readme_path)
end
end
it '"Add License" button linked to new file populated for a license' do
page.within('.project-stats') do
- expect(page).to have_link('Add License', href: add_special_file_path(project, file_name: 'LICENSE'))
+ expect(page).to have_link('Add License', href: presenter.add_license_path)
end
end
@@ -121,6 +120,7 @@ describe 'Project show page', :feature do
describe 'populated project' do
let(:project) { create(:project, :public, :repository) }
+ let(:presenter) { project.present(current_user: user) }
describe 'as a normal user' do
before do
@@ -192,7 +192,7 @@ describe 'Project show page', :feature do
expect(project.repository.gitlab_ci_yml).to be_nil
page.within('.project-stats') do
- expect(page).to have_link('Set up CI/CD', href: add_special_file_path(project, file_name: '.gitlab-ci.yml'))
+ expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_path)
end
end
@@ -327,7 +327,7 @@ describe 'Project show page', :feature do
visit project_path(project)
page.within('.project-stats') do
- expect(page).to have_link('Set up Koding', href: add_koding_stack_path(project))
+ expect(page).to have_link('Set up Koding', href: presenter.add_koding_stack_path)
end
end
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index c0251bf7dc0..ffe4266b51a 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -264,32 +264,6 @@ describe ProjectsHelper do
end
end
- describe '#license_short_name' do
- let(:project) { create(:project) }
-
- context 'when project.repository has a license_key' do
- it 'returns the nickname of the license if present' do
- allow(project.repository).to receive(:license_key).and_return('agpl-3.0')
-
- expect(helper.license_short_name(project)).to eq('GNU AGPLv3')
- end
-
- it 'returns the name of the license if nickname is not present' do
- allow(project.repository).to receive(:license_key).and_return('mit')
-
- expect(helper.license_short_name(project)).to eq('MIT License')
- end
- end
-
- context 'when project.repository has no license_key but a license_blob' do
- it 'returns LICENSE' do
- allow(project.repository).to receive(:license_key).and_return(nil)
-
- expect(helper.license_short_name(project)).to eq('LICENSE')
- end
- end
- end
-
describe '#sanitized_import_error' do
let(:project) { create(:project, :repository) }
diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb
new file mode 100644
index 00000000000..49822693f3e
--- /dev/null
+++ b/spec/presenters/project_presenter_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe ProjectPresenter do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:presenter) { described_class.new(project, current_user: user) }
+
+ describe '#license_short_name' do
+ context 'when project.repository has a license_key' do
+ it 'returns the nickname of the license if present' do
+ allow(project.repository).to receive(:license_key).and_return('agpl-3.0')
+
+ expect(presenter.license_short_name).to eq('GNU AGPLv3')
+ end
+
+ it 'returns the name of the license if nickname is not present' do
+ allow(project.repository).to receive(:license_key).and_return('mit')
+
+ expect(presenter.license_short_name).to eq('MIT License')
+ end
+ end
+
+ context 'when project.repository has no license_key but a license_blob' do
+ it 'returns LICENSE' do
+ allow(project.repository).to receive(:license_key).and_return(nil)
+
+ expect(presenter.license_short_name).to eq('LICENSE')
+ end
+ end
+ end
+end