diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-29 18:08:47 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-29 18:08:47 +0000 |
commit | 6b9d3a4e8351e662c4586b24bb152de78ae9e3bf (patch) | |
tree | 883e9db60c047c54418fc1d2b1c5517f97e0f185 /app | |
parent | 23288f62da73fb0e30d8e7ce306665e8fda1b932 (diff) | |
download | gitlab-ce-6b9d3a4e8351e662c4586b24bb152de78ae9e3bf.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
33 files changed, 255 insertions, 167 deletions
diff --git a/app/assets/javascripts/editor/editor_lite.js b/app/assets/javascripts/editor/editor_lite.js new file mode 100644 index 00000000000..bdfbcf71267 --- /dev/null +++ b/app/assets/javascripts/editor/editor_lite.js @@ -0,0 +1,68 @@ +import { editor as monacoEditor, languages as monacoLanguages, Uri } from 'monaco-editor'; +import gitlabTheme from '~/ide/lib/themes/gl_theme'; +import { defaultEditorOptions } from '~/ide/lib/editor_options'; +import { clearDomElement } from './utils'; + +export default class Editor { + constructor(options = {}) { + this.editorEl = null; + this.blobContent = ''; + this.blobPath = ''; + this.instance = null; + this.model = null; + this.options = { + ...defaultEditorOptions, + ...options, + }; + + Editor.setupMonacoTheme(); + } + + static setupMonacoTheme() { + monacoEditor.defineTheme(gitlabTheme.themeName, gitlabTheme.monacoTheme); + monacoEditor.setTheme('gitlab'); + } + + createInstance({ el = undefined, blobPath = '', blobContent = '' } = {}) { + if (!el) return; + this.editorEl = el; + this.blobContent = blobContent; + this.blobPath = blobPath; + + clearDomElement(this.editorEl); + + this.model = monacoEditor.createModel( + this.blobContent, + undefined, + new Uri('gitlab', false, this.blobPath), + ); + + monacoEditor.onDidCreateEditor(this.renderEditor.bind(this)); + + this.instance = monacoEditor.create(this.editorEl, this.options); + this.instance.setModel(this.model); + } + + dispose() { + return this.instance && this.instance.dispose(); + } + + renderEditor() { + delete this.editorEl.dataset.editorLoading; + } + + updateModelLanguage(path) { + if (path === this.blobPath) return; + this.blobPath = path; + const ext = `.${path.split('.').pop()}`; + const language = monacoLanguages + .getLanguages() + .find(lang => lang.extensions.indexOf(ext) !== -1); + const id = language ? language.id : 'plaintext'; + monacoEditor.setModelLanguage(this.model, id); + } + + getValue() { + return this.model.getValue(); + } +} diff --git a/app/assets/javascripts/editor/utils.js b/app/assets/javascripts/editor/utils.js new file mode 100644 index 00000000000..d8b6396b671 --- /dev/null +++ b/app/assets/javascripts/editor/utils.js @@ -0,0 +1,11 @@ +export const clearDomElement = el => { + if (!el || !el.firstChild) return; + + while (el.firstChild) { + el.removeChild(el.firstChild); + } +}; + +export default () => ({ + clearDomElement, +}); diff --git a/app/assets/javascripts/ide/lib/editor.js b/app/assets/javascripts/ide/lib/editor.js index d1056ea6b98..a0f689065aa 100644 --- a/app/assets/javascripts/ide/lib/editor.js +++ b/app/assets/javascripts/ide/lib/editor.js @@ -8,20 +8,13 @@ import ModelManager from './common/model_manager'; import editorOptions, { defaultEditorOptions } from './editor_options'; import gitlabTheme from './themes/gl_theme'; import keymap from './keymap.json'; +import { clearDomElement } from '~/editor/utils'; function setupMonacoTheme() { monacoEditor.defineTheme(gitlabTheme.themeName, gitlabTheme.monacoTheme); monacoEditor.setTheme('gitlab'); } -export const clearDomElement = el => { - if (!el || !el.firstChild) return; - - while (el.firstChild) { - el.removeChild(el.firstChild); - } -}; - export default class Editor { static create(options = {}) { if (!this.editorInstance) { diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue index 75c3c544c77..9ec99ac93d7 100644 --- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue @@ -41,7 +41,7 @@ export default { changedIcon() { // False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26 // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings - const suffix = !this.file.changed && this.file.staged && this.showStagedIcon ? '-solid' : ''; + const suffix = this.file.staged && this.showStagedIcon ? '-solid' : ''; return `${getCommitIconMap(this.file).icon}${suffix}`; }, @@ -49,25 +49,19 @@ export default { return `${this.changedIcon} float-left d-block`; }, tooltipTitle() { - if (!this.showTooltip) return undefined; + if (!this.showTooltip || !this.file.changed) return undefined; const type = this.file.tempFile ? 'addition' : 'modification'; - if (this.file.changed && !this.file.staged) { - return sprintf(__('Unstaged %{type}'), { - type, - }); - } else if (!this.file.changed && this.file.staged) { + if (this.file.staged) { return sprintf(__('Staged %{type}'), { type, }); - } else if (this.file.changed && this.file.staged) { - return sprintf(__('Unstaged and staged %{type}'), { - type, - }); } - return undefined; + return sprintf(__('Unstaged %{type}'), { + type, + }); }, showIcon() { return ( diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 79ad0bd7735..c14ae8a3711 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -21,10 +21,6 @@ margin-left: 8px; } - .btn-group { - margin-left: 10px; - } - .control { float: left; margin-left: 10px; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c6d91308123..789bccf268a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -120,7 +120,7 @@ class ApplicationController < ActionController::Base def render(*args) super.tap do # Set a header for custom error pages to prevent them from being intercepted by gitlab-workhorse - if (400..599).cover?(response.status) && workhorse_excluded_content_types.include?(response.content_type) + if (400..599).cover?(response.status) && workhorse_excluded_content_types.include?(response.media_type) response.headers['X-GitLab-Custom-Error'] = '1' end end diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb index 993f091b0e6..1cf9046e30f 100644 --- a/app/controllers/concerns/membership_actions.rb +++ b/app/controllers/concerns/membership_actions.rb @@ -21,9 +21,9 @@ module MembershipActions member = Members::UpdateService .new(current_user, update_params) .execute(member) - .present(current_user: current_user) - present_members([member]) + member = present_members([member]).first + respond_to do |format| format.js { render 'shared/members/update', locals: { member: member } } end diff --git a/app/controllers/concerns/send_file_upload.rb b/app/controllers/concerns/send_file_upload.rb index 28e4cece548..2f5dc09be4a 100644 --- a/app/controllers/concerns/send_file_upload.rb +++ b/app/controllers/concerns/send_file_upload.rb @@ -3,7 +3,7 @@ module SendFileUpload def send_upload(file_upload, send_params: {}, redirect_params: {}, attachment: nil, proxy: false, disposition: 'attachment') if attachment - response_disposition = ::Gitlab::ContentDisposition.format(disposition: disposition, filename: attachment) + response_disposition = ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: attachment) # Response-Content-Type will not override an existing Content-Type in # Google Cloud Storage, so the metadata needs to be cleared on GCS for @@ -15,7 +15,7 @@ module SendFileUpload # cross-origin JavaScript protection. send_params[:content_type] = 'text/plain' if File.extname(attachment) == '.js' - send_params.merge!(filename: attachment, disposition: utf8_encoded_disposition(disposition, attachment)) + send_params.merge!(filename: attachment, disposition: disposition) end if file_upload.file_storage? @@ -28,18 +28,6 @@ module SendFileUpload end end - # Since Rails 5 doesn't properly support support non-ASCII filenames, - # we have to add our own to ensure RFC 5987 compliance. However, Rails - # 5 automatically appends `filename#{filename}` here: - # https://github.com/rails/rails/blob/v5.0.7/actionpack/lib/action_controller/metal/data_streaming.rb#L137 - # Rails 6 will have https://github.com/rails/rails/pull/33829, so we - # can get rid of this special case handling when we upgrade. - def utf8_encoded_disposition(disposition, filename) - content = ::Gitlab::ContentDisposition.new(disposition: disposition, filename: filename) - - "#{disposition}; #{content.utf8_filename}" - end - def guess_content_type(filename) types = MIME::Types.type_for(filename) diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb index 08a57a9b146..7ad841d645d 100644 --- a/app/controllers/projects/releases_controller.rb +++ b/app/controllers/projects/releases_controller.rb @@ -3,11 +3,12 @@ class Projects::ReleasesController < Projects::ApplicationController # Authorize before_action :require_non_empty_project, except: [:index] - before_action :release, only: %i[edit update] + before_action :release, only: %i[edit show update] before_action :authorize_read_release! before_action do push_frontend_feature_flag(:release_issue_summary, project) push_frontend_feature_flag(:release_evidence_collection, project, default_enabled: true) + push_frontend_feature_flag(:release_show_page, project) end before_action :authorize_update_release!, only: %i[edit update] before_action :authorize_read_release_evidence!, only: [:evidence] @@ -29,6 +30,16 @@ class Projects::ReleasesController < Projects::ApplicationController end end + def show + return render_404 unless Feature.enabled?(:release_show_page, project) + + respond_to do |format| + format.html do + render :show + end + end + end + protected def releases @@ -37,7 +48,9 @@ class Projects::ReleasesController < Projects::ApplicationController def edit respond_to do |format| - format.html { render 'edit' } + format.html do + render :edit + end end end diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb index e24d6a0e8db..e42ea3861b8 100644 --- a/app/helpers/markup_helper.rb +++ b/app/helpers/markup_helper.rb @@ -4,7 +4,7 @@ require 'nokogiri' module MarkupHelper include ActionView::Helpers::TextHelper - include ::Gitlab::ActionViewOutput::Context + include ActionView::Context def plain?(filename) Gitlab::MarkupHelper.plain?(filename) diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index f9101609f89..5a917588a33 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -200,6 +200,10 @@ class CommitStatus < ApplicationRecord update_all('processed=TRUE, lock_version=COALESCE(lock_version,0)+1') end + def self.locking_enabled? + false + end + def locking_enabled? will_save_change_to_status? end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 653dc9c0b47..a6961df1b51 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -130,6 +130,10 @@ module Issuable strip_attributes :title + def self.locking_enabled? + false + end + # We want to use optimistic lock for cases when only title or description are involved # http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html def locking_enabled? diff --git a/app/models/concerns/mirror_authentication.rb b/app/models/concerns/mirror_authentication.rb index 948094221e5..4dbf4dcec77 100644 --- a/app/models/concerns/mirror_authentication.rb +++ b/app/models/concerns/mirror_authentication.rb @@ -37,6 +37,8 @@ module MirrorAuthentication end define_method("#{name}=") do |value| + credentials_will_change! + self.credentials ||= {} # Removal of the password, username, etc, generally causes an update of diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 3174a3269b4..62f34ae6525 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -712,7 +712,7 @@ class MergeRequest < ApplicationRecord end def validate_branch_name(attr) - return unless changes_include?(attr) + return unless will_save_change_to_attribute?(attr) branch = read_attribute(attr) diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index 2b3443f24d7..1447f822513 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -21,7 +21,10 @@ class NotificationSetting < ApplicationRecord # pending delete). # scope :for_projects, -> do - includes(:project).references(:projects).where(source_type: 'Project').where.not(projects: { id: nil, pending_delete: true }) + includes(:project).references(:projects) + .where(source_type: 'Project') + .where.not(projects: { id: nil }) + .where.not(projects: { pending_delete: true }) end EMAIL_EVENTS = [ diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb index 8c24d07675a..42c707908e6 100644 --- a/app/presenters/project_presenter.rb +++ b/app/presenters/project_presenter.rb @@ -208,7 +208,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated AnchorData.new(false, statistic_icon + _('New file'), project_new_blob_path(project, default_branch || 'master'), - 'success') + 'missing') end end diff --git a/app/serializers/concerns/user_status_tooltip.rb b/app/serializers/concerns/user_status_tooltip.rb index a81e377691e..633b117d392 100644 --- a/app/serializers/concerns/user_status_tooltip.rb +++ b/app/serializers/concerns/user_status_tooltip.rb @@ -3,7 +3,7 @@ module UserStatusTooltip extend ActiveSupport::Concern include ActionView::Helpers::TagHelper - include ::Gitlab::ActionViewOutput::Context + include ActionView::Context include EmojiHelper include UsersHelper diff --git a/app/services/concerns/spam_check_methods.rb b/app/services/concerns/spam_check_methods.rb index 5eb663c97ff..695bdf92b49 100644 --- a/app/services/concerns/spam_check_methods.rb +++ b/app/services/concerns/spam_check_methods.rb @@ -23,7 +23,7 @@ module SpamCheckMethods # attribute values. # rubocop:disable Gitlab/ModuleWithInstanceVariables def spam_check(spammable, user) - SpamCheckService.new( + Spam::SpamCheckService.new( spammable: spammable, request: @request ).execute( diff --git a/app/services/metrics/dashboard/clone_dashboard_service.rb b/app/services/metrics/dashboard/clone_dashboard_service.rb index b2ec44cb814..990dc462432 100644 --- a/app/services/metrics/dashboard/clone_dashboard_service.rb +++ b/app/services/metrics/dashboard/clone_dashboard_service.rb @@ -8,8 +8,18 @@ module Metrics ALLOWED_FILE_TYPE = '.yml' USER_DASHBOARDS_DIR = ::Metrics::Dashboard::ProjectDashboardService::DASHBOARD_ROOT - def self.allowed_dashboard_templates - @allowed_dashboard_templates ||= Set[::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH].freeze + class << self + def allowed_dashboard_templates + @allowed_dashboard_templates ||= Set[::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH].freeze + end + + def sequences + @sequences ||= { + ::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH => [::Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter, + ::Gitlab::Metrics::Dashboard::Stages::ProjectMetricsInserter, + ::Gitlab::Metrics::Dashboard::Stages::Sorter].freeze + }.freeze + end end def execute @@ -92,7 +102,9 @@ module Metrics end def new_dashboard_content - File.read(Rails.root.join(dashboard_template)) + ::Gitlab::Metrics::Dashboard::Processor + .new(project, raw_dashboard, sequence, {}) + .process.deep_stringify_keys.to_yaml end def repository @@ -106,6 +118,14 @@ module Metrics result end end + + def raw_dashboard + YAML.safe_load(File.read(Rails.root.join(dashboard_template))) + end + + def sequence + self.class.sequences[dashboard_template] + end end end end diff --git a/app/services/projects/detect_repository_languages_service.rb b/app/services/projects/detect_repository_languages_service.rb index d3680637217..942cd8162e4 100644 --- a/app/services/projects/detect_repository_languages_service.rb +++ b/app/services/projects/detect_repository_languages_service.rb @@ -12,7 +12,7 @@ module Projects matching_programming_languages = ensure_programming_languages(detection) RepositoryLanguage.transaction do - project.repository_languages.where(programming_language_id: detection.deletions).delete_all + RepositoryLanguage.where(project_id: project.id, programming_language_id: detection.deletions).delete_all detection.updates.each do |update| RepositoryLanguage diff --git a/app/services/projects/move_access_service.rb b/app/services/projects/move_access_service.rb index 8e2c3ad2f69..cddc544170f 100644 --- a/app/services/projects/move_access_service.rb +++ b/app/services/projects/move_access_service.rb @@ -20,6 +20,8 @@ module Projects ::Projects::MoveProjectAuthorizationsService.new(@project, @current_user) .execute(source_project, remove_remaining_elements: remove_remaining_elements) + @project.save(touch: false) + success end end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 718416a03d4..309eab59463 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -13,8 +13,6 @@ module Projects include Gitlab::ShellAdapter TransferError = Class.new(StandardError) - attr_reader :new_namespace - def execute(new_namespace) @new_namespace = new_namespace @@ -39,6 +37,8 @@ module Projects private + attr_reader :old_path, :new_path, :new_namespace + # rubocop: disable CodeReuse/ActiveRecord def transfer(project) @old_path = project.full_path @@ -132,6 +132,8 @@ module Projects end def rollback_folder_move + return if project.hashed_storage?(:repository) + move_repo_folder(@new_path, @old_path) move_repo_folder("#{@new_path}.wiki", "#{@old_path}.wiki") end diff --git a/app/services/spam/spam_check_service.rb b/app/services/spam/spam_check_service.rb new file mode 100644 index 00000000000..d19ef03976f --- /dev/null +++ b/app/services/spam/spam_check_service.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module Spam + class SpamCheckService + include AkismetMethods + + attr_accessor :spammable, :request, :options + attr_reader :spam_log + + def initialize(spammable:, request:) + @spammable = spammable + @request = request + @options = {} + + if @request + @options[:ip_address] = @request.env['action_dispatch.remote_ip'].to_s + @options[:user_agent] = @request.env['HTTP_USER_AGENT'] + @options[:referrer] = @request.env['HTTP_REFERRER'] + else + @options[:ip_address] = @spammable.ip_address + @options[:user_agent] = @spammable.user_agent + end + end + + def execute(api: false, recaptcha_verified:, spam_log_id:, user_id:) + if recaptcha_verified + # If it's a request which is already verified through recaptcha, + # update the spam log accordingly. + SpamLog.verify_recaptcha!(user_id: user_id, id: spam_log_id) + else + # Otherwise, it goes to Akismet for spam check. + # If so, it assigns spammable object as "spam" and creates a SpamLog record. + possible_spam = check(api) + spammable.spam = possible_spam unless spammable.allow_possible_spam? + spammable.spam_log = spam_log + end + end + + private + + def check(api) + return unless request + return unless check_for_spam? + return unless akismet.spam? + + create_spam_log(api) + true + end + + def check_for_spam? + spammable.check_for_spam? + end + + def create_spam_log(api) + @spam_log = SpamLog.create!( + { + user_id: spammable.author_id, + title: spammable.spam_title, + description: spammable.spam_description, + source_ip: options[:ip_address], + user_agent: options[:user_agent], + noteable_type: spammable.class.to_s, + via_api: api + } + ) + end + end +end diff --git a/app/services/spam_check_service.rb b/app/services/spam_check_service.rb deleted file mode 100644 index e1f5efabcaf..00000000000 --- a/app/services/spam_check_service.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -class SpamCheckService - include AkismetMethods - - attr_accessor :spammable, :request, :options - attr_reader :spam_log - - def initialize(spammable:, request:) - @spammable = spammable - @request = request - @options = {} - - if @request - @options[:ip_address] = @request.env['action_dispatch.remote_ip'].to_s - @options[:user_agent] = @request.env['HTTP_USER_AGENT'] - @options[:referrer] = @request.env['HTTP_REFERRER'] - else - @options[:ip_address] = @spammable.ip_address - @options[:user_agent] = @spammable.user_agent - end - end - - def execute(api: false, recaptcha_verified:, spam_log_id:, user_id:) - if recaptcha_verified - # If it's a request which is already verified through recaptcha, - # update the spam log accordingly. - SpamLog.verify_recaptcha!(user_id: user_id, id: spam_log_id) - else - # Otherwise, it goes to Akismet for spam check. - # If so, it assigns spammable object as "spam" and creates a SpamLog record. - possible_spam = check(api) - spammable.spam = possible_spam unless spammable.allow_possible_spam? - spammable.spam_log = spam_log - end - end - - private - - def check(api) - return unless request - return unless check_for_spam? - return unless akismet.spam? - - create_spam_log(api) - true - end - - def check_for_spam? - spammable.check_for_spam? - end - - def create_spam_log(api) - @spam_log = SpamLog.create!( - { - user_id: spammable.author_id, - title: spammable.spam_title, - description: spammable.spam_description, - source_ip: options[:ip_address], - user_agent: options[:user_agent], - noteable_type: spammable.class.to_s, - via_api: api - } - ) - end -end diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb index 36bde629f9c..450ebb00b49 100644 --- a/app/uploaders/object_storage.rb +++ b/app/uploaders/object_storage.rb @@ -125,7 +125,7 @@ module ObjectStorage included do include AfterCommitQueue - after_save on: [:create, :update] do + after_save do background_upload(changed_mounts) end end diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index daedc52f298..7796db5ba63 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -49,13 +49,6 @@ = render 'projects/buttons/star' = render 'projects/buttons/fork' - - if can?(current_user, :download_code, @project) - .project-clone-holder.d-inline-flex.d-md-none.btn-block - = render "shared/mobile_clone_panel" - - .project-clone-holder.d-none.d-md-inline-flex - = render "projects/buttons/clone" - - if can?(current_user, :download_code, @project) %nav.project-stats .nav-links.quick-links diff --git a/app/views/projects/buttons/_clone.html.haml b/app/views/projects/buttons/_clone.html.haml index ed22573b23e..7507be52f44 100644 --- a/app/views/projects/buttons/_clone.html.haml +++ b/app/views/projects/buttons/_clone.html.haml @@ -1,11 +1,12 @@ - project = project || @project +- dropdown_class = local_assigns.fetch(:dropdown_class, '') -.git-clone-holder.js-git-clone-holder.input-group - %a#clone-dropdown.input-group-text.btn.btn-primary.btn-xs.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } } +.git-clone-holder.js-git-clone-holder + %a#clone-dropdown.btn.btn-primary.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } } %span.append-right-4.js-clone-dropdown-label = _('Clone') = sprite_icon("arrow-down", css_class: "icon") - %ul.p-3.dropdown-menu.dropdown-menu-right.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown.qa-clone-options + %ul.p-3.dropdown-menu.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown.qa-clone-options{ class: dropdown_class } - if ssh_enabled? %li %label.label-bold diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index a9b6b397968..9e06358beba 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -11,9 +11,14 @@ - if @project.can_current_user_push_code? %p.append-bottom-0 - = _('You can create files directly in GitLab using one of the following options.') + = _('You can get started by cloning the repository or start adding files to it with one of the following options.') .project-buttons.qa-quick-actions + .project-clone-holder.d-block.d-md-none.mt-2.mr-2 + = render "shared/mobile_clone_panel" + + .project-clone-holder.d-none.d-md-inline-block.mt-2.mr-2.float-left + = render "projects/buttons/clone" = render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons - if can?(current_user, :push_code, @project) diff --git a/app/views/projects/network/show.json.erb b/app/views/projects/network/show.json.erb index a0e82e891ff..a146d137c55 100644 --- a/app/views/projects/network/show.json.erb +++ b/app/views/projects/network/show.json.erb @@ -1,4 +1,4 @@ -<% self.formats = ["html"] %> +<% self.formats = [:html] %> <%= raw( { diff --git a/app/views/projects/releases/show.html.haml b/app/views/projects/releases/show.html.haml new file mode 100644 index 00000000000..188262fb34c --- /dev/null +++ b/app/views/projects/releases/show.html.haml @@ -0,0 +1,4 @@ +- add_to_breadcrumbs _("Releases"), project_releases_path(@project) +- page_title @release.name + +#js-show-release-page{ data: { project_id: @project.id, tag_name: @release.tag } } diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml index 2d987744dfd..52a11642f32 100644 --- a/app/views/projects/tree/_tree_header.html.haml +++ b/app/views/projects/tree/_tree_header.html.haml @@ -101,3 +101,9 @@ = render "projects/buttons/xcode_link" = render 'projects/buttons/download', project: @project, ref: @ref + + .project-clone-holder.d-block.d-md-none.mt-sm-2.mt-md-0> + = render "shared/mobile_clone_panel" + + .project-clone-holder.d-none.d-md-inline-block> + = render "projects/buttons/clone", dropdown_class: 'dropdown-menu-right' diff --git a/app/views/shared/_mobile_clone_panel.html.haml b/app/views/shared/_mobile_clone_panel.html.haml index 2887acf7cd7..df2ed5cfd97 100644 --- a/app/views/shared/_mobile_clone_panel.html.haml +++ b/app/views/shared/_mobile_clone_panel.html.haml @@ -4,7 +4,7 @@ .btn-group.mobile-git-clone.js-mobile-git-clone.btn-block = clipboard_button(button_text: default_clone_label, text: default_url_to_repo(project), hide_button_icon: true, class: "btn-primary flex-fill bold justify-content-center input-group-text clone-dropdown-btn js-clone-dropdown-label") - %button.btn.btn-primary.dropdown-toggle.js-dropdown-toggle.flex-grow-0.d-flex-center{ type: "button", data: { toggle: "dropdown" } } + %button.btn.btn-primary.dropdown-toggle.js-dropdown-toggle.flex-grow-0.d-flex-center.w-auto.ml-0{ type: "button", data: { toggle: "dropdown" } } = sprite_icon("arrow-down", css_class: "dropdown-btn-icon icon") %ul.dropdown-menu.dropdown-menu-selectable.dropdown-menu-right.clone-options-dropdown{ data: { dropdown: true } } - if ssh_enabled? diff --git a/app/workers/mail_scheduler/notification_service_worker.rb b/app/workers/mail_scheduler/notification_service_worker.rb index 4130ce25878..ec659e39b24 100644 --- a/app/workers/mail_scheduler/notification_service_worker.rb +++ b/app/workers/mail_scheduler/notification_service_worker.rb @@ -26,49 +26,26 @@ module MailScheduler end def self.perform_async(*args) - super(*Arguments.serialize(args)) + super(*ActiveJob::Arguments.serialize(args)) end private - # If an argument is in the ActiveJob::Arguments::TYPE_WHITELIST list, + # This is copied over from https://github.com/rails/rails/blob/v6.0.1/activejob/lib/active_job/arguments.rb#L50 + # because it is declared as a private constant + PERMITTED_TYPES = [NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass].freeze + + private_constant :PERMITTED_TYPES + + # If an argument is in the PERMITTED_TYPES list, # it means the argument cannot be deserialized. # Which means there's something wrong with our code. def check_arguments!(args) args.each do |arg| - if arg.class.in?(ActiveJob::Arguments::TYPE_WHITELIST) + if arg.class.in?(PERMITTED_TYPES) raise(ArgumentError, "Argument `#{arg}` cannot be deserialized because of its type") end end end - - # Permit ActionController::Parameters for serializable Hash - # - # Port of - # https://github.com/rails/rails/commit/945fdd76925c9f615bf016717c4c8db2b2955357#diff-fc90ec41ef75be8b2259526fe1a8b663 - module Arguments - include ActiveJob::Arguments - extend self - - private - - def serialize_argument(argument) - case argument - when -> (arg) { arg.respond_to?(:permitted?) } - serialize_hash(argument.to_h).tap do |result| - result[WITH_INDIFFERENT_ACCESS_KEY] = serialize_argument(true) - end - else - super - end - end - end - - # Make sure we remove this patch starting with Rails 6.0. - if Rails.version.start_with?('6.0') - raise <<~MSG - Please remove the patch `Arguments` module and use `ActiveJob::Arguments` again. - MSG - end end end |