Skip to content
Snippets Groups Projects
Commit 0ab47b99 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 1308dc5e
No related branches found
No related tags found
No related merge requests found
Showing
with 219 additions and 45 deletions
Loading
Loading
@@ -6,7 +6,6 @@ class Snippet < ApplicationRecord
include CacheMarkdownField
include Noteable
include Participable
include Referable
include Sortable
include Awardable
include Mentionable
Loading
Loading
@@ -15,10 +14,11 @@ class Snippet < ApplicationRecord
include Gitlab::SQL::Pattern
include FromUnion
include IgnorableColumns
include HasRepository
extend ::Gitlab::Utils::Override
 
ignore_column :storage_version, remove_with: '12.9', remove_after: '2020-03-22'
ignore_column :repository_storage, remove_with: '12.10', remove_after: '2020-04-22'
 
cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :description
Loading
Loading
@@ -42,6 +42,7 @@ class Snippet < ApplicationRecord
 
has_many :notes, as: :noteable, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :user_mentions, class_name: "SnippetUserMention"
has_one :snippet_repository, inverse_of: :snippet
 
delegate :name, :email, to: :author, prefix: true, allow_nil: true
 
Loading
Loading
@@ -254,6 +255,47 @@ class Snippet < ApplicationRecord
super
end
 
def repository
@repository ||= Repository.new(full_path, self, disk_path: disk_path, repo_type: Gitlab::GlRepository::SNIPPET)
end
def storage
@storage ||= Storage::Hashed.new(self, prefix: Storage::Hashed::SNIPPET_REPOSITORY_PATH_PREFIX)
end
# This is the full_path used to identify the
# the snippet repository. It will be used mostly
# for logging purposes.
def full_path
return unless persisted?
@full_path ||= begin
components = []
components << project.full_path if project_id?
components << '@snippets'
components << self.id
components.join('/')
end
end
def repository_storage
snippet_repository&.shard_name ||
Gitlab::CurrentSettings.pick_repository_storage
end
def create_repository
return if repository_exists?
repository.create_if_not_exists
track_snippet_repository if repository_exists?
end
def track_snippet_repository
repository = snippet_repository || build_snippet_repository
repository.update!(shard_name: repository_storage, disk_path: disk_path)
end
class << self
# Searches for snippets with a matching title or file name.
#
Loading
Loading
# frozen_string_literal: true
class SnippetRepository < ApplicationRecord
include Shardable
belongs_to :snippet, inverse_of: :snippet_repository
class << self
def find_snippet(disk_path)
find_by(disk_path: disk_path)&.snippet
end
end
end
Loading
Loading
@@ -2,14 +2,15 @@
 
module Storage
class Hashed
attr_accessor :project
delegate :gitlab_shell, :repository_storage, to: :project
attr_accessor :container
delegate :gitlab_shell, :repository_storage, to: :container
 
REPOSITORY_PATH_PREFIX = '@hashed'
SNIPPET_REPOSITORY_PATH_PREFIX = '@snippets'
POOL_PATH_PREFIX = '@pools'
 
def initialize(project, prefix: REPOSITORY_PATH_PREFIX)
@project = project
def initialize(container, prefix: REPOSITORY_PATH_PREFIX)
@container = container
@prefix = prefix
end
 
Loading
Loading
@@ -20,9 +21,10 @@ module Storage
"#{@prefix}/#{disk_hash[0..1]}/#{disk_hash[2..3]}" if disk_hash
end
 
# Disk path is used to build repository and project's wiki path on disk
# Disk path is used to build repository path on disk
#
# @return [String] combination of base_dir and the repository own name without `.git` or `.wiki.git` extensions
# @return [String] combination of base_dir and the repository own name
# without `.git`, `.wiki.git`, or any other extension
def disk_path
"#{base_dir}/#{disk_hash}" if disk_hash
end
Loading
Loading
@@ -33,10 +35,10 @@ module Storage
 
private
 
# Generates the hash for the project path and name on disk
# Generates the hash for the repository path and name on disk
# If you need to refer to the repository on disk, use the `#disk_path`
def disk_hash
@disk_hash ||= Digest::SHA2.hexdigest(project.id.to_s) if project.id
@disk_hash ||= Digest::SHA2.hexdigest(container.id.to_s) if container.id
end
end
end
Loading
Loading
@@ -5,13 +5,7 @@ module Boards
def execute(create_default_board: true)
create_board! if create_default_board && parent.boards.empty?
 
if parent.multiple_issue_boards_available?
boards
else
# When multiple issue boards are not available
# a user is only allowed to view the default shown board
first_board
end
find_boards
end
 
private
Loading
Loading
@@ -27,5 +21,18 @@ module Boards
def create_board!
Boards::CreateService.new(parent, current_user).execute
end
def find_boards
found =
if parent.multiple_issue_boards_available?
boards
else
# When multiple issue boards are not available
# a user is only allowed to view the default shown board
first_board
end
params[:board_id].present? ? [found.find(params[:board_id])] : found
end
end
end
Loading
Loading
@@ -6,9 +6,11 @@ class ContainerExpirationPolicyService < BaseService
 
container_expiration_policy.container_repositories.find_each do |container_repository|
CleanupContainerRepositoryWorker.perform_async(
current_user.id,
nil,
container_repository.id,
container_expiration_policy.attributes.except("created_at", "updated_at")
container_expiration_policy.attributes
.except('created_at', 'updated_at')
.merge(container_expiration_policy: true)
)
end
end
Loading
Loading
# frozen_string_literal: true
# Fetches the self monitoring metrics dashboard and formats the output.
# Use Gitlab::Metrics::Dashboard::Finder to retrieve dashboards.
module Metrics
module Dashboard
class SelfMonitoringDashboardService < ::Metrics::Dashboard::PredefinedDashboardService
DASHBOARD_PATH = 'config/prometheus/self_monitoring_default.yml'
DASHBOARD_NAME = 'Default'
SEQUENCE = [
STAGES::ProjectMetricsInserter,
STAGES::EndpointInserter,
STAGES::Sorter
].freeze
class << self
def valid_params?(params)
matching_dashboard?(params[:dashboard_path]) || self_monitoring_project?(params)
end
def all_dashboard_paths(_project)
[{
path: DASHBOARD_PATH,
display_name: DASHBOARD_NAME,
default: true,
system_dashboard: false
}]
end
def self_monitoring_project?(params)
params[:dashboard_path].nil? && params[:environment]&.project&.self_monitoring?
end
end
end
end
end
Loading
Loading
@@ -5,7 +5,7 @@ module Projects
class CleanupTagsService < BaseService
def execute(container_repository)
return error('feature disabled') unless can_use?
return error('access denied') unless can_admin?
return error('access denied') unless can_destroy?
 
tags = container_repository.tags
tags_by_digest = group_by_digest(tags)
Loading
Loading
@@ -82,8 +82,10 @@ module Projects
end
end
 
def can_admin?
can?(current_user, :admin_container_image, project)
def can_destroy?
return true if params['container_expiration_policy']
can?(current_user, :destroy_container_image, project)
end
 
def can_use?
Loading
Loading
Loading
Loading
@@ -42,7 +42,7 @@ module Projects
# Deletes the dummy image
# All created tag digests are the same since they all have the same dummy image.
# a single delete is sufficient to remove all tags with it
if deleted_tags.any? && container_repository.delete_tag_by_digest(deleted_tags.values.first)
if deleted_tags.any? && container_repository.delete_tag_by_digest(deleted_tags.each_value.first)
success(deleted: deleted_tags.keys)
else
error('could not delete tags')
Loading
Loading
# frozen_string_literal: true
module Users
class BlockService < BaseService
def initialize(current_user)
@current_user = current_user
end
def execute(user)
if user.block
after_block_hook(user)
success
else
messages = user.errors.full_messages
error(messages.uniq.join('. '))
end
end
private
def after_block_hook(user)
# overriden by EE module
end
end
end
Users::BlockService.prepend_if_ee('EE::Users::BlockService')
Loading
Loading
@@ -5,4 +5,5 @@
%i.fa.fa-rss
 
.content_list
= spinner
.loading
.spinner.spinner-md
- add_to_breadcrumbs _("Snippets"), project_snippets_path(@project)
- breadcrumb_title @snippet.to_reference
- page_title _("Edit"), "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
- @content_class = "limit-container-width" unless fluid_layout
 
%h3.page-title
= _("Edit Snippet")
Loading
Loading
- add_to_breadcrumbs _("Snippets"), project_snippets_path(@project)
- breadcrumb_title _("New")
- page_title _("New Snippet")
- @content_class = "limit-container-width" unless fluid_layout
 
%h3.page-title
= _("New Snippet")
Loading
Loading
Loading
Loading
@@ -6,27 +6,37 @@
html: { class: "snippet-form js-requires-input js-quick-submit common-note-form" } do |f|
= form_errors(@snippet)
 
.form-group.row
.col-sm-2.col-form-label
= f.label :title
.col-sm-10
= f.text_field :title, class: 'form-control qa-snippet-title', required: true, autofocus: true
= render 'shared/form_elements/description', model: @snippet, project: @project, form: f
= render 'shared/old_visibility_level', f: f, visibility_level: @snippet.visibility_level, can_change_visibility_level: true, form_model: @snippet, with_label: false
.file-editor
.form-group.row
.col-sm-2.col-form-label
= f.label :file_name, "File"
.col-sm-10
.file-holder.snippet
.js-file-title.file-title-flex-parent
= f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name qa-snippet-file-name'
.file-content.code
%pre#editor= @snippet.content
= f.hidden_field :content, class: 'snippet-file-content'
.form-group
= f.label :title, class: 'label-bold'
= f.text_field :title, class: 'form-control qa-snippet-title', required: true, autofocus: true
.form-group.js-description-input
- description_placeholder = s_('Snippets|Optionally add a description about what your snippet does or how to use it...')
- is_expanded = @snippet.description && !@snippet.description.empty?
= f.label :description, s_("Snippets|Description (optional)"), class: 'label-bold'
.js-collapsible-input
.js-collapsed{ class: ('d-none' if is_expanded) }
= text_field_tag nil, nil, class: 'form-control', placeholder: description_placeholder
.js-expanded{ class: ('d-none' if !is_expanded) }
= render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
= render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: description_placeholder
= render 'shared/notes/hints'
.form-group.file-editor
= f.label :file_name, s_('Snippets|File')
.file-holder.snippet
.js-file-title.file-title-flex-parent
= f.text_field :file_name, placeholder: s_("Snippets|Give your file a name to add code highlighting, e.g. example.rb for Ruby"), class: 'form-control snippet-file-name qa-snippet-file-name'
.file-content.code
%pre#editor= @snippet.content
= f.hidden_field :content, class: 'snippet-file-content'
.form-group
.font-weight-bold
= _('Visibility level')
= link_to icon('question-circle'), help_page_path("public_access/public_access"), target: '_blank'
= render 'shared/visibility_level', f: f, visibility_level: @snippet.visibility_level, can_change_visibility_level: true, form_model: @snippet, with_label: false
- if params[:files]
- params[:files].each_with_index do |file, index|
= hidden_field_tag "files[]", file, id: "files_#{index}"
Loading
Loading
- page_title _("Edit"), "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
- @content_class = "limit-container-width" unless fluid_layout
 
%h3.page-title
= _("Edit Snippet")
Loading
Loading
- @hide_top_links = true
- @hide_breadcrumbs = true
- page_title _("New Snippet")
- @content_class = "limit-container-width" unless fluid_layout
 
.page-title-holder.d-flex.align-items-center
%h1.page-title= _('New Snippet')
Loading
Loading
Loading
Loading
@@ -11,6 +11,7 @@ class CleanupContainerRepositoryWorker
def perform(current_user_id, container_repository_id, params)
@current_user = User.find_by_id(current_user_id)
@container_repository = ContainerRepository.find_by_id(container_repository_id)
@params = params
 
return unless valid?
 
Loading
Loading
@@ -22,9 +23,15 @@ class CleanupContainerRepositoryWorker
private
 
def valid?
return true if run_by_container_expiration_policy?
current_user && container_repository && project
end
 
def run_by_container_expiration_policy?
@params['container_expiration_policy'] && container_repository && project
end
def project
container_repository&.project
end
Loading
Loading
---
title: Set default dashboard for self monitoring project
merge_request: 24814
author:
type: added
---
title: Display the y-axis on the range of data value in the chart
merge_request: 24953
author:
type: added
---
title: Improve UX of optional fields in Snippets form
merge_request: 24762
author:
type: other
---
title: Create snippet repository model
merge_request: 23796
author:
type: added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment