From 6b9d3a4e8351e662c4586b24bb152de78ae9e3bf Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 29 Jan 2020 18:08:47 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .rubocop.yml | 6 - Gemfile | 5 +- Gemfile.lock | 129 +++++++++-------- app/assets/javascripts/editor/editor_lite.js | 68 +++++++++ app/assets/javascripts/editor/utils.js | 11 ++ app/assets/javascripts/ide/lib/editor.js | 9 +- .../vue_shared/components/changed_file_icon.vue | 18 +-- app/assets/stylesheets/pages/tree.scss | 4 - app/controllers/application_controller.rb | 2 +- app/controllers/concerns/membership_actions.rb | 4 +- app/controllers/concerns/send_file_upload.rb | 16 +-- app/controllers/projects/releases_controller.rb | 17 ++- app/helpers/markup_helper.rb | 2 +- app/models/commit_status.rb | 4 + app/models/concerns/issuable.rb | 4 + app/models/concerns/mirror_authentication.rb | 2 + app/models/merge_request.rb | 2 +- app/models/notification_setting.rb | 5 +- app/presenters/project_presenter.rb | 2 +- app/serializers/concerns/user_status_tooltip.rb | 2 +- app/services/concerns/spam_check_methods.rb | 2 +- .../metrics/dashboard/clone_dashboard_service.rb | 26 +++- .../detect_repository_languages_service.rb | 2 +- app/services/projects/move_access_service.rb | 2 + app/services/projects/transfer_service.rb | 6 +- app/services/spam/spam_check_service.rb | 68 +++++++++ app/services/spam_check_service.rb | 66 --------- app/uploaders/object_storage.rb | 2 +- app/views/projects/_home_panel.html.haml | 7 - app/views/projects/buttons/_clone.html.haml | 7 +- app/views/projects/empty.html.haml | 7 +- app/views/projects/network/show.json.erb | 2 +- app/views/projects/releases/show.html.haml | 4 + app/views/projects/tree/_tree_header.html.haml | 6 + app/views/shared/_mobile_clone_panel.html.haml | 2 +- .../mail_scheduler/notification_service_worker.rb | 41 ++---- bin/setup | 12 +- ...ification-tooltip-for-file-with-staged-chan.yml | 5 + changelogs/unreleased/31034-upgrade-to-rails-6.yml | 5 + ...one-a-dashboard-so-it-would-copy-the-custom.yml | 6 + ...move-clone-button-to-the-tree-controls-area.yml | 5 + config/application.rb | 4 +- config/environment.rb | 5 +- config/environments/development.rb | 4 + config/initializers/active_record_data_types.rb | 11 +- config/initializers/active_record_preloader.rb | 2 +- config/initializers/active_record_query_cache.rb | 3 - .../config_initializers_active_record_locking.rb | 2 +- config/initializers/content_security_policy.rb | 1 + config/initializers/cookies_serializer.rb | 1 + config/routes/project.rb | 2 +- db/schema.rb | 10 +- doc/development/packages.md | 2 +- lib/api/helpers.rb | 4 +- lib/gitlab/action_view_output/context.rb | 41 ------ lib/gitlab/ci/config/external/file/template.rb | 2 +- lib/gitlab/content_disposition.rb | 54 -------- lib/gitlab/database.rb | 7 +- lib/gitlab/database/migration_helpers.rb | 6 +- lib/gitlab/patch/active_record_query_cache.rb | 39 ------ lib/gitlab/query_limiting/middleware.rb | 4 +- locale/ar_SA/gitlab.po | 3 - locale/bg/gitlab.po | 3 - locale/bn_BD/gitlab.po | 3 - locale/bn_IN/gitlab.po | 3 - locale/ca_ES/gitlab.po | 3 - locale/cs_CZ/gitlab.po | 3 - locale/cy_GB/gitlab.po | 3 - locale/da_DK/gitlab.po | 3 - locale/de/gitlab.po | 3 - locale/el_GR/gitlab.po | 3 - locale/eo/gitlab.po | 3 - locale/es/gitlab.po | 3 - locale/et_EE/gitlab.po | 3 - locale/fa_IR/gitlab.po | 3 - locale/fil_PH/gitlab.po | 3 - locale/fr/gitlab.po | 3 - locale/gitlab.pot | 9 +- locale/gl_ES/gitlab.po | 3 - locale/he_IL/gitlab.po | 3 - locale/hi_IN/gitlab.po | 3 - locale/hr_HR/gitlab.po | 3 - locale/hu_HU/gitlab.po | 3 - locale/id_ID/gitlab.po | 3 - locale/it/gitlab.po | 3 - locale/ja/gitlab.po | 3 - locale/ka_GE/gitlab.po | 3 - locale/ko/gitlab.po | 3 - locale/ku_TR/gitlab.po | 3 - locale/ml_IN/gitlab.po | 3 - locale/mn_MN/gitlab.po | 3 - locale/nb_NO/gitlab.po | 3 - locale/nl_NL/gitlab.po | 3 - locale/pa_IN/gitlab.po | 3 - locale/pl_PL/gitlab.po | 3 - locale/pt_BR/gitlab.po | 3 - locale/pt_PT/gitlab.po | 3 - locale/ro_RO/gitlab.po | 3 - locale/ru/gitlab.po | 3 - locale/sk_SK/gitlab.po | 3 - locale/sq_AL/gitlab.po | 3 - locale/sr_CS/gitlab.po | 3 - locale/sr_SP/gitlab.po | 3 - locale/sv_SE/gitlab.po | 3 - locale/sw_KE/gitlab.po | 3 - locale/tr_TR/gitlab.po | 3 - locale/uk/gitlab.po | 3 - locale/ur_PK/gitlab.po | 3 - locale/uz_UZ/gitlab.po | 3 - locale/vi_VN/gitlab.po | 3 - locale/zh_CN/gitlab.po | 3 - locale/zh_HK/gitlab.po | 3 - locale/zh_TW/gitlab.po | 3 - rubocop/cop/include_action_view_context.rb | 26 ---- rubocop/rubocop.rb | 1 - spec/config/application_spec.rb | 2 +- .../controllers/concerns/metrics_dashboard_spec.rb | 2 +- spec/controllers/concerns/send_file_upload_spec.rb | 24 +--- .../projects/artifacts_controller_spec.rb | 12 +- .../projects/releases_controller_spec.rb | 46 ++++++- spec/controllers/uploads_controller_spec.rb | 2 +- .../merge_request/user_sees_merge_widget_spec.rb | 4 +- .../artifacts/user_downloads_artifacts_spec.rb | 2 +- spec/features/projects/jobs_spec.rb | 2 +- .../components/changed_file_icon_spec.js | 12 +- spec/javascripts/editor/editor_lite_spec.js | 111 +++++++++++++++ spec/lib/gitlab/database/migration_helpers_spec.rb | 2 +- spec/lib/gitlab/query_limiting/middleware_spec.rb | 4 +- spec/models/merge_request_spec.rb | 6 +- spec/presenters/project_presenter_spec.rb | 2 +- .../api/issues/post_projects_issues_spec.rb | 2 +- .../api/issues/put_projects_issues_spec.rb | 2 +- .../cop/include_action_view_context_spec.rb | 45 ------ spec/services/akismet_service_spec.rb | 1 - spec/services/issues/create_service_spec.rb | 2 +- .../dashboard/clone_dashboard_service_spec.rb | 27 ++-- spec/services/projects/transfer_service_spec.rb | 38 +++-- spec/services/spam/spam_check_service_spec.rb | 153 +++++++++++++++++++++ spec/services/spam_check_service_spec.rb | 153 --------------------- .../support/helpers/javascript_fixtures_helpers.rb | 2 +- spec/support/helpers/migrations_helpers.rb | 2 +- spec/support/helpers/stub_configuration.rb | 1 - .../repository_lfs_file_load_shared_examples.rb | 4 +- .../services/metrics/dashboard_shared_examples.rb | 35 +++++ 144 files changed, 817 insertions(+), 871 deletions(-) create mode 100644 app/assets/javascripts/editor/editor_lite.js create mode 100644 app/assets/javascripts/editor/utils.js create mode 100644 app/services/spam/spam_check_service.rb delete mode 100644 app/services/spam_check_service.rb create mode 100644 app/views/projects/releases/show.html.haml create mode 100644 changelogs/unreleased/197973-staged-and-unstaged-modification-tooltip-for-file-with-staged-chan.yml create mode 100644 changelogs/unreleased/31034-upgrade-to-rails-6.yml create mode 100644 changelogs/unreleased/39505-extend-the-ability-to-clone-a-dashboard-so-it-would-copy-the-custom.yml create mode 100644 changelogs/unreleased/gt-move-clone-button-to-the-tree-controls-area.yml delete mode 100644 config/initializers/active_record_query_cache.rb delete mode 100644 lib/gitlab/action_view_output/context.rb delete mode 100644 lib/gitlab/content_disposition.rb delete mode 100644 lib/gitlab/patch/active_record_query_cache.rb delete mode 100644 rubocop/cop/include_action_view_context.rb create mode 100644 spec/javascripts/editor/editor_lite_spec.js delete mode 100644 spec/rubocop/cop/include_action_view_context_spec.rb create mode 100644 spec/services/spam/spam_check_service_spec.rb delete mode 100644 spec/services/spam_check_service_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index 46419e69e7e..1e34dc2480b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -235,12 +235,6 @@ RSpec/FactoriesInMigrationSpecs: - 'spec/lib/ee/gitlab/background_migration/**/*.rb' - 'ee/spec/lib/ee/gitlab/background_migration/**/*.rb' -Cop/IncludeActionViewContext: - Enabled: true - Exclude: - - 'spec/**/*' - - 'ee/spec/**/*' - Cop/IncludeSidekiqWorker: Enabled: true Exclude: diff --git a/Gemfile b/Gemfile index b8e7ba12b56..e816e1a1fcd 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'rails', '5.2.3' +gem 'rails', '6.0.2' gem 'bootsnap', '~> 1.4' @@ -305,7 +305,7 @@ gem 'gitlab-labkit', '0.9.1' # I18n gem 'ruby_parser', '~> 3.8', require: false -gem 'rails-i18n', '~> 5.1' +gem 'rails-i18n', '~> 6.0' gem 'gettext_i18n_rails', '~> 1.8.0' gem 'gettext_i18n_rails_js', '~> 1.3' gem 'gettext', '~> 3.2.2', require: false, group: :development @@ -332,6 +332,7 @@ group :metrics do end group :development do + gem 'listen', '~> 3.0' gem 'brakeman', '~> 4.2', require: false gem 'danger', '~> 6.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index f7bc7441741..c52150cc675 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,50 +6,64 @@ GEM ace-rails-ap (4.1.2) acme-client (2.0.5) faraday (~> 0.9, >= 0.9.1) - actioncable (5.2.3) - actionpack (= 5.2.3) + actioncable (6.0.2) + actionpack (= 6.0.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.3) - actionpack (= 5.2.3) - actionview (= 5.2.3) - activejob (= 5.2.3) + actionmailbox (6.0.2) + actionpack (= 6.0.2) + activejob (= 6.0.2) + activerecord (= 6.0.2) + activestorage (= 6.0.2) + activesupport (= 6.0.2) + mail (>= 2.7.1) + actionmailer (6.0.2) + actionpack (= 6.0.2) + actionview (= 6.0.2) + activejob (= 6.0.2) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.3) - actionview (= 5.2.3) - activesupport (= 5.2.3) + actionpack (6.0.2) + actionview (= 6.0.2) + activesupport (= 6.0.2) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.3) - activesupport (= 5.2.3) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.0.2) + actionpack (= 6.0.2) + activerecord (= 6.0.2) + activestorage (= 6.0.2) + activesupport (= 6.0.2) + nokogiri (>= 1.8.5) + actionview (6.0.2) + activesupport (= 6.0.2) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.3) - activesupport (= 5.2.3) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.0.2) + activesupport (= 6.0.2) globalid (>= 0.3.6) - activemodel (5.2.3) - activesupport (= 5.2.3) - activerecord (5.2.3) - activemodel (= 5.2.3) - activesupport (= 5.2.3) - arel (>= 9.0) + activemodel (6.0.2) + activesupport (= 6.0.2) + activerecord (6.0.2) + activemodel (= 6.0.2) + activesupport (= 6.0.2) activerecord-explain-analyze (0.1.0) activerecord (>= 4) pg - activestorage (5.2.3) - actionpack (= 5.2.3) - activerecord (= 5.2.3) + activestorage (6.0.2) + actionpack (= 6.0.2) + activejob (= 6.0.2) + activerecord (= 6.0.2) marcel (~> 0.3.1) - activesupport (5.2.3) + activesupport (6.0.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) + zeitwerk (~> 2.2) acts-as-taggable-on (6.5.0) activerecord (>= 5.0, < 6.1) adamantium (0.2.0) @@ -62,7 +76,6 @@ GEM apollo_upload_server (2.0.0.beta.3) graphql (>= 1.8) rails (>= 4.2) - arel (9.0.0) asana (0.9.3) faraday (~> 0.9) faraday_middleware (~> 0.9) @@ -198,13 +211,14 @@ GEM declarative-option (0.1.0) default_value_for (3.3.0) activerecord (>= 3.2.0, < 6.1) - derailed_benchmarks (1.3.5) + derailed_benchmarks (1.4.2) benchmark-ips (~> 2) get_process_mem (~> 0) heapy (~> 0) memory_profiler (~> 0) rack (>= 1) - rake (> 10, < 13) + rake (> 10, < 14) + ruby-statistics (>= 2.1) thor (~> 0.19) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) @@ -348,7 +362,8 @@ GEM gemoji (3.0.1) gemojione (3.3.0) json - get_process_mem (0.2.3) + get_process_mem (0.2.5) + ffi (~> 1.0) gettext (3.2.9) locale (>= 2.0.5) text (>= 1.3.0) @@ -434,8 +449,9 @@ GEM activesupport grape (~> 1.0) rake (~> 12) - grape_logging (1.7.0) + grape_logging (1.8.3) grape + rack graphiql-rails (1.4.10) railties sprockets-rails @@ -510,7 +526,7 @@ GEM mime-types (~> 3.0) multi_xml (>= 0.5.2) httpclient (2.8.3) - i18n (1.7.1) + i18n (1.7.0) concurrent-ruby (~> 1.0) i18n_data (0.8.0) icalendar (2.4.1) @@ -609,12 +625,12 @@ GEM memoist (0.16.0) memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) - memory_profiler (0.9.13) + memory_profiler (0.9.14) method_source (0.9.2) mime-types (3.2.2) mime-types-data (~> 3.2015) mime-types-data (3.2019.0331) - mimemagic (0.3.2) + mimemagic (0.3.3) mini_magick (4.9.5) mini_mime (1.0.2) mini_portile2 (2.4.0) @@ -787,18 +803,20 @@ GEM rack-test (1.1.0) rack (>= 1.0, < 3) rack-timeout (0.5.1) - rails (5.2.3) - actioncable (= 5.2.3) - actionmailer (= 5.2.3) - actionpack (= 5.2.3) - actionview (= 5.2.3) - activejob (= 5.2.3) - activemodel (= 5.2.3) - activerecord (= 5.2.3) - activestorage (= 5.2.3) - activesupport (= 5.2.3) + rails (6.0.2) + actioncable (= 6.0.2) + actionmailbox (= 6.0.2) + actionmailer (= 6.0.2) + actionpack (= 6.0.2) + actiontext (= 6.0.2) + actionview (= 6.0.2) + activejob (= 6.0.2) + activemodel (= 6.0.2) + activerecord (= 6.0.2) + activestorage (= 6.0.2) + activesupport (= 6.0.2) bundler (>= 1.3.0) - railties (= 5.2.3) + railties (= 6.0.2) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.4) actionpack (>= 5.0.1.x) @@ -809,15 +827,15 @@ GEM nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - rails-i18n (5.1.1) + rails-i18n (6.0.0) i18n (>= 0.7, < 2) - railties (>= 5.0, < 6) - railties (5.2.3) - actionpack (= 5.2.3) - activesupport (= 5.2.3) + railties (>= 6.0.0, < 7) + railties (6.0.2) + actionpack (= 6.0.2) + activesupport (= 6.0.2) method_source rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) + thor (>= 0.20.3, < 2.0) rainbow (3.0.0) raindrops (0.19.0) rake (12.3.3) @@ -937,6 +955,7 @@ GEM ruby-progressbar (1.10.1) ruby-saml (1.7.2) nokogiri (>= 1.5.10) + ruby-statistics (2.1.1) ruby_dep (1.5.0) ruby_parser (3.13.1) sexp_processor (~> 4.9) @@ -1111,9 +1130,9 @@ GEM hashdiff webpack-rails (0.9.11) railties (>= 3.2.0) - websocket-driver (0.7.0) + websocket-driver (0.7.1) websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.3) + websocket-extensions (0.1.4) wikicloth (0.8.1) builder expression_parser @@ -1122,6 +1141,7 @@ GEM xml-simple (1.1.5) xpath (3.2.0) nokogiri (~> 1.8) + zeitwerk (2.2.2) PLATFORMS ruby @@ -1259,6 +1279,7 @@ DEPENDENCIES license_finder (~> 5.4) licensee (~> 8.9) liquid (~> 4.0) + listen (~> 3.0) lograge (~> 0.5) loofah (~> 2.2) lru_redux @@ -1309,9 +1330,9 @@ DEPENDENCIES rack-oauth2 (~> 1.9.3) rack-proxy (~> 0.6.0) rack-timeout - rails (= 5.2.3) + rails (= 6.0.2) rails-controller-testing - rails-i18n (~> 5.1) + rails-i18n (~> 6.0) rainbow (~> 3.0) raindrops (~> 0.18) rblineprof (~> 0.3.6) 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 diff --git a/bin/setup b/bin/setup index 94fd4d79775..5853b5ea875 100755 --- a/bin/setup +++ b/bin/setup @@ -1,6 +1,5 @@ #!/usr/bin/env ruby require 'fileutils' -include FileUtils # path to your application root. APP_ROOT = File.expand_path('..', __dir__) @@ -9,24 +8,25 @@ def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") end -chdir APP_ROOT do - # This script is a starting point to setup your application. +FileUtils.chdir APP_ROOT do + # This script is a way to setup or update your development environment automatically. + # This script is idempotent, so that you can run it at anytime and get an expectable outcome. # Add necessary setup steps to this file. puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') - # Install JavaScript dependencies if using Yarn + # Install JavaScript dependencies # system('bin/yarn') # puts "\n== Copying sample files ==" # unless File.exist?('config/database.yml') - # cp 'config/database.yml.sample', 'config/database.yml' + # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' # end puts "\n== Preparing database ==" - system! 'bin/rails db:setup' + system! 'bin/rails db:prepare' puts "\n== Removing old logs and tempfiles ==" system! 'bin/rails log:clear tmp:clear' diff --git a/changelogs/unreleased/197973-staged-and-unstaged-modification-tooltip-for-file-with-staged-chan.yml b/changelogs/unreleased/197973-staged-and-unstaged-modification-tooltip-for-file-with-staged-chan.yml new file mode 100644 index 00000000000..3b0a8d335ff --- /dev/null +++ b/changelogs/unreleased/197973-staged-and-unstaged-modification-tooltip-for-file-with-staged-chan.yml @@ -0,0 +1,5 @@ +--- +title: Remove unstaged and staged modification tooltip +merge_request: 23847 +author: +type: fixed diff --git a/changelogs/unreleased/31034-upgrade-to-rails-6.yml b/changelogs/unreleased/31034-upgrade-to-rails-6.yml new file mode 100644 index 00000000000..e1f6958d43a --- /dev/null +++ b/changelogs/unreleased/31034-upgrade-to-rails-6.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade to Rails 6 +merge_request: 19891 +author: +type: other diff --git a/changelogs/unreleased/39505-extend-the-ability-to-clone-a-dashboard-so-it-would-copy-the-custom.yml b/changelogs/unreleased/39505-extend-the-ability-to-clone-a-dashboard-so-it-would-copy-the-custom.yml new file mode 100644 index 00000000000..256cef1115f --- /dev/null +++ b/changelogs/unreleased/39505-extend-the-ability-to-clone-a-dashboard-so-it-would-copy-the-custom.yml @@ -0,0 +1,6 @@ +--- +title: Extends 'Duplicate dashboard' feature, by including custom metrics added to + GitLab-defined dashboards. +merge_request: 21923 +author: +type: added diff --git a/changelogs/unreleased/gt-move-clone-button-to-the-tree-controls-area.yml b/changelogs/unreleased/gt-move-clone-button-to-the-tree-controls-area.yml new file mode 100644 index 00000000000..ba6efd070ed --- /dev/null +++ b/changelogs/unreleased/gt-move-clone-button-to-the-tree-controls-area.yml @@ -0,0 +1,5 @@ +--- +title: Move the clone button to the tree controls area +merge_request: 17752 +author: Ablay Keldibek +type: changed diff --git a/config/application.rb b/config/application.rb index 304cd72e806..e8cc35aed2a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,7 +1,9 @@ require_relative 'boot' -# Based on https://github.com/rails/rails/blob/v5.2.3/railties/lib/rails/all.rb +# Based on https://github.com/rails/rails/blob/v6.0.1/railties/lib/rails/all.rb # Only load the railties we need instead of loading everything +require 'rails' + require 'active_record/railtie' require 'action_controller/railtie' require 'action_view/railtie' diff --git a/config/environment.rb b/config/environment.rb index 7e55c7803d3..426333bb469 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,6 +1,5 @@ -# Load the rails application - +# Load the Rails application. require_relative 'application' -# Initialize the rails application +# Initialize the Rails application. Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb index dc804197fef..960892a1dc2 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -50,4 +50,8 @@ Rails.application.configure do # BetterErrors live shell (REPL) on every stack frame BetterErrors::Middleware.allow_ip!("127.0.0.1/0") + + # Use an evented file watcher to asynchronously detect changes in source code, + # routes, locales, etc. This feature depends on the listen gem. + config.file_watcher = ActiveSupport::EventedFileUpdateChecker end diff --git a/config/initializers/active_record_data_types.rb b/config/initializers/active_record_data_types.rb index 2b3f58330e3..3fa999e9908 100644 --- a/config/initializers/active_record_data_types.rb +++ b/config/initializers/active_record_data_types.rb @@ -24,10 +24,11 @@ module RegisterDateTimeWithTimeZone def initialize_type_map(mapping = type_map) super mapping - mapping.register_type 'timestamptz' do |_, _, sql_type| - precision = extract_precision(sql_type) - ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::DateTimeWithTimeZone.new(precision: precision) - end + register_class_with_precision( + mapping, + 'timestamptz', + ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::DateTimeWithTimeZone + ) end end @@ -46,3 +47,5 @@ end if (ActiveRecord::Base.connection.active? rescue false) ActiveRecord::Base.connection.send :reload_type_map end + +ActiveRecord::Base.time_zone_aware_types += [:datetime_with_timezone] diff --git a/config/initializers/active_record_preloader.rb b/config/initializers/active_record_preloader.rb index a293909149e..d585ecda307 100644 --- a/config/initializers/active_record_preloader.rb +++ b/config/initializers/active_record_preloader.rb @@ -6,7 +6,7 @@ module ActiveRecord self end - def self.run(preloader) + def self.run end def self.preloaded_records diff --git a/config/initializers/active_record_query_cache.rb b/config/initializers/active_record_query_cache.rb deleted file mode 100644 index 61505a1edd3..00000000000 --- a/config/initializers/active_record_query_cache.rb +++ /dev/null @@ -1,3 +0,0 @@ -# frozen_string_literal: true - -ActiveRecord::ConnectionAdapters::ConnectionPool.prepend Gitlab::Patch::ActiveRecordQueryCache diff --git a/config/initializers/config_initializers_active_record_locking.rb b/config/initializers/config_initializers_active_record_locking.rb index 915247826e9..9f9908283c6 100644 --- a/config/initializers/config_initializers_active_record_locking.rb +++ b/config/initializers/config_initializers_active_record_locking.rb @@ -26,7 +26,7 @@ module ActiveRecord locking_column => possible_previous_lock_value, self.class.primary_key => id_in_database ).update_all( - attributes_with_values_for_update(attribute_names) + attributes_with_values(attribute_names) ) if affected_rows != 1 diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 608d0401a96..c19fb65017f 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -12,4 +12,5 @@ if csp_settings['enabled'] Rails.application.config.content_security_policy_report_only = csp_settings['report_only'] Rails.application.config.content_security_policy_nonce_generator = ->(request) { SecureRandom.base64(16) } + Rails.application.config.content_security_policy_nonce_directives = %w(script-src) end diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb index 54516e3f23d..a04d5044f4e 100644 --- a/config/initializers/cookies_serializer.rb +++ b/config/initializers/cookies_serializer.rb @@ -1,3 +1,4 @@ # Be sure to restart your server when you modify this file. +Rails.application.config.action_dispatch.use_cookies_with_metadata = false Rails.application.config.action_dispatch.cookies_serializer = :hybrid diff --git a/config/routes/project.rb b/config/routes/project.rb index 68568db1326..352184ed746 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -166,7 +166,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do end end - resources :releases, only: [:index, :edit], param: :tag, constraints: { tag: %r{[^/]+} } do + resources :releases, only: [:index, :show, :edit], param: :tag, constraints: { tag: %r{[^/]+} } do member do get :evidence end diff --git a/db/schema.rb b/db/schema.rb index 88c456322dd..cb27967e69c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -2,11 +2,11 @@ # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). +# This file is the source Rails uses to define your schema when running `rails +# db:schema:load`. When creating a new database, `rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. # # It's strongly recommended that you check this file into your version control system. diff --git a/doc/development/packages.md b/doc/development/packages.md index 8722bb1e710..c433864600f 100644 --- a/doc/development/packages.md +++ b/doc/development/packages.md @@ -7,7 +7,7 @@ See already supported package types in [Packages documentation](../administratio Since GitLab packages' UI is pretty generic, it is possible to add basic new package system support with solely backend changes. This guide is superficial and does not cover the way the code should be written. However, you can find a good example -by looking at existing merge requests with Maven and NPM support: +by looking at merge requests with Maven and NPM support: - [NPM registry support](https://gitlab.com/gitlab-org/gitlab/merge_requests/8673). - [Conan repository](https://gitlab.com/gitlab-org/gitlab/issues/8248). diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index aa6071e6099..688b1cc6f17 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -434,7 +434,7 @@ module API def present_disk_file!(path, filename, content_type = 'application/octet-stream') filename ||= File.basename(path) - header['Content-Disposition'] = ::Gitlab::ContentDisposition.format(disposition: 'attachment', filename: filename) + header['Content-Disposition'] = ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: filename) header['Content-Transfer-Encoding'] = 'binary' content_type content_type @@ -542,7 +542,7 @@ module API def send_git_blob(repository, blob) env['api.format'] = :txt content_type 'text/plain' - header['Content-Disposition'] = ::Gitlab::ContentDisposition.format(disposition: 'inline', filename: blob.name) + header['Content-Disposition'] = ActionDispatch::Http::ContentDisposition.format(disposition: 'inline', filename: blob.name) # Let Workhorse examine the content and determine the better content disposition header[Gitlab::Workhorse::DETECT_HEADER] = "true" diff --git a/lib/gitlab/action_view_output/context.rb b/lib/gitlab/action_view_output/context.rb deleted file mode 100644 index 9fbc9811636..00000000000 --- a/lib/gitlab/action_view_output/context.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -# This file was simplified from https://raw.githubusercontent.com/rails/rails/195f39804a7a4a0034f25e8704220e03d95a752a/actionview/lib/action_view/context.rb. -# -# It is only needed by modules that need to call ActionView helper -# methods (e.g. those in -# https://github.com/rails/rails/tree/c4d3e202e10ae627b3b9c34498afb45450652421/actionview/lib/action_view/helpers) -# to generate tags outside of a Rails controller (e.g. API, Sidekiq, -# etc.). -# -# In Rails 5, ActionView::Context automatically includes CompiledTemplates. -# This means that any module that includes ActionView::Context is now a descendant -# of CompiledTemplates. -# -# When a partial is rendered for the first time, it runs -# Module#module_eval, which will evaluate a string source that defines a -# new method. For example: -# -# def _app_views_profiles_show_html_haml___1285955918103175884_70307801785400(local_assigns, output_buffer) -# "hello world" -# end -# -# When a new method is defined, the Ruby interpreter clears the method -# cache for all descendants, and all methods for those modules will have -# to be redefined. This can lead to a significant performance penalty. -# -# Rails 6 fixes this behavior by moving out the `include -# CompiledTemplates` into ActionView::Base so that including `ActionView::Context` -# doesn't quietly affect other modules in this way. - -if Rails::VERSION::STRING.start_with?('6') - raise 'This module is no longer needed in Rails 6. Use ActionView::Context instead.' -end - -module Gitlab - module ActionViewOutput - module Context - attr_accessor :output_buffer, :view_flow - end - end -end diff --git a/lib/gitlab/ci/config/external/file/template.rb b/lib/gitlab/ci/config/external/file/template.rb index db56f6a9b00..c4b4a7a0a73 100644 --- a/lib/gitlab/ci/config/external/file/template.rb +++ b/lib/gitlab/ci/config/external/file/template.rb @@ -33,7 +33,7 @@ module Gitlab def template_name return unless template_name_valid? - location.first(-SUFFIX.length) + location.delete_suffix(SUFFIX) end def template_name_valid? diff --git a/lib/gitlab/content_disposition.rb b/lib/gitlab/content_disposition.rb deleted file mode 100644 index ff6154a5b26..00000000000 --- a/lib/gitlab/content_disposition.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true -# This ports ActionDispatch::Http::ContentDisposition (https://github.com/rails/rails/pull/33829, -# which will be available in Rails 6. -module Gitlab - class ContentDisposition # :nodoc: - # Make sure we remove this patch starting with Rails 6.0. - if Rails.version.start_with?('6.0') - raise <<~MSG - Please remove this file and use `ActionDispatch::Http::ContentDisposition` instead. - MSG - end - - def self.format(disposition:, filename:) - new(disposition: disposition, filename: filename).to_s - end - - attr_reader :disposition, :filename - - def initialize(disposition:, filename:) - @disposition = disposition - @filename = filename - end - - # rubocop:disable Style/VariableInterpolation - TRADITIONAL_ESCAPED_CHAR = /[^ A-Za-z0-9!#$+.^_`|~-]/.freeze - - def ascii_filename - 'filename="' + percent_escape(::I18n.transliterate(filename), TRADITIONAL_ESCAPED_CHAR) + '"' - end - - RFC_5987_ESCAPED_CHAR = /[^A-Za-z0-9!#$&+.^_`|~-]/.freeze - # rubocop:enable Style/VariableInterpolation - - def utf8_filename - "filename*=UTF-8''" + percent_escape(filename, RFC_5987_ESCAPED_CHAR) - end - - def to_s - if filename - "#{disposition}; #{ascii_filename}; #{utf8_filename}" - else - "#{disposition}" - end - end - - private - - def percent_escape(string, pattern) - string.gsub(pattern) do |char| - char.bytes.map { |byte| "%%%02X" % byte }.join - end - end - end -end diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb index 82ec740ade1..a614e68703c 100644 --- a/lib/gitlab/database.rb +++ b/lib/gitlab/database.rb @@ -204,15 +204,16 @@ module Gitlab # pool_size - The size of the DB pool. # host - An optional host name to use instead of the default one. def self.create_connection_pool(pool_size, host = nil, port = nil) - # See activerecord-4.2.7.1/lib/active_record/connection_adapters/connection_specification.rb env = Rails.env - original_config = ActiveRecord::Base.configurations + original_config = ActiveRecord::Base.configurations.to_h env_config = original_config[env].merge('pool' => pool_size) env_config['host'] = host if host env_config['port'] = port if port - config = original_config.merge(env => env_config) + config = ActiveRecord::DatabaseConfigurations.new( + original_config.merge(env => env_config) + ) spec = ActiveRecord:: diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index b53e01e6ff2..3b6684b861c 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -382,7 +382,7 @@ module Gitlab count_arel = table.project(Arel.star.count.as('count')) count_arel = yield table, count_arel if block_given? - total = exec_query(count_arel.to_sql).to_hash.first['count'].to_i + total = exec_query(count_arel.to_sql).to_a.first['count'].to_i return if total == 0 @@ -399,7 +399,7 @@ module Gitlab start_arel = table.project(table[:id]).order(table[:id].asc).take(1) start_arel = yield table, start_arel if block_given? - start_id = exec_query(start_arel.to_sql).to_hash.first['id'].to_i + start_id = exec_query(start_arel.to_sql).to_a.first['id'].to_i loop do stop_arel = table.project(table[:id]) @@ -409,7 +409,7 @@ module Gitlab .skip(batch_size) stop_arel = yield table, stop_arel if block_given? - stop_row = exec_query(stop_arel.to_sql).to_hash.first + stop_row = exec_query(stop_arel.to_sql).to_a.first update_arel = Arel::UpdateManager.new .table(table) diff --git a/lib/gitlab/patch/active_record_query_cache.rb b/lib/gitlab/patch/active_record_query_cache.rb deleted file mode 100644 index d6b649cdea7..00000000000 --- a/lib/gitlab/patch/active_record_query_cache.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -# Fixes a bug where the query cache isn't aware of the shared -# ActiveRecord connection used in tests -# https://github.com/rails/rails/issues/36587 - -# To be removed with https://gitlab.com/gitlab-org/gitlab-foss/issues/64413 - -module Gitlab - module Patch - module ActiveRecordQueryCache - # rubocop:disable Gitlab/ModuleWithInstanceVariables - def enable_query_cache! - @query_cache_enabled[connection_cache_key(current_thread)] = true - connection.enable_query_cache! if active_connection? - end - - def disable_query_cache! - @query_cache_enabled.delete connection_cache_key(current_thread) - connection.disable_query_cache! if active_connection? - end - - def query_cache_enabled - @query_cache_enabled[connection_cache_key(current_thread)] - end - - def active_connection? - @thread_cached_conns[connection_cache_key(current_thread)] - end - - private - - def current_thread - @lock_thread || Thread.current - end - # rubocop:enable Gitlab/ModuleWithInstanceVariables - end - end -end diff --git a/lib/gitlab/query_limiting/middleware.rb b/lib/gitlab/query_limiting/middleware.rb index f6ffbfe2645..714fe42884a 100644 --- a/lib/gitlab/query_limiting/middleware.rb +++ b/lib/gitlab/query_limiting/middleware.rb @@ -37,10 +37,10 @@ module Gitlab controller = env[CONTROLLER_KEY] action = "#{controller.class.name}##{controller.action_name}" - if controller.content_type == 'text/html' + if controller.media_type == 'text/html' action else - "#{action} (#{controller.content_type})" + "#{action} (#{controller.media_type})" end end diff --git a/locale/ar_SA/gitlab.po b/locale/ar_SA/gitlab.po index 55bee3a2dc7..6d369b69a37 100644 --- a/locale/ar_SA/gitlab.po +++ b/locale/ar_SA/gitlab.po @@ -20432,9 +20432,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po index 8643995d451..0b3ee37cbc6 100644 --- a/locale/bg/gitlab.po +++ b/locale/bg/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "Без звезда" diff --git a/locale/bn_BD/gitlab.po b/locale/bn_BD/gitlab.po index 883057b9f9d..3807e1da453 100644 --- a/locale/bn_BD/gitlab.po +++ b/locale/bn_BD/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/bn_IN/gitlab.po b/locale/bn_IN/gitlab.po index e530dec967f..5703e27cb8b 100644 --- a/locale/bn_IN/gitlab.po +++ b/locale/bn_IN/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/ca_ES/gitlab.po b/locale/ca_ES/gitlab.po index 9eeba969661..7f509f06f52 100644 --- a/locale/ca_ES/gitlab.po +++ b/locale/ca_ES/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/cs_CZ/gitlab.po b/locale/cs_CZ/gitlab.po index 7c424b45001..60dfcbbeb53 100644 --- a/locale/cs_CZ/gitlab.po +++ b/locale/cs_CZ/gitlab.po @@ -20226,9 +20226,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/cy_GB/gitlab.po b/locale/cy_GB/gitlab.po index c4c9680ed06..73d1f97c9ef 100644 --- a/locale/cy_GB/gitlab.po +++ b/locale/cy_GB/gitlab.po @@ -20432,9 +20432,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/da_DK/gitlab.po b/locale/da_DK/gitlab.po index 338d82e86a8..24777c04104 100644 --- a/locale/da_DK/gitlab.po +++ b/locale/da_DK/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po index d1f013f3317..2ca8f20d2c2 100644 --- a/locale/de/gitlab.po +++ b/locale/de/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "Nicht vorgemerkt" msgid "Unstaged %{type}" msgstr "Nicht vorgemerkt %{type}" -msgid "Unstaged and staged %{type}" -msgstr "Nicht vorgemerkt und vorgemerkt %{type}" - msgid "Unstar" msgstr "Entfavorisieren" diff --git a/locale/el_GR/gitlab.po b/locale/el_GR/gitlab.po index b52569855aa..204c779fba0 100644 --- a/locale/el_GR/gitlab.po +++ b/locale/el_GR/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po index 294b41a3ba7..82cc7c0116d 100644 --- a/locale/eo/gitlab.po +++ b/locale/eo/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "Malsteligi" diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po index 9d8779cc77c..2614f39949c 100644 --- a/locale/es/gitlab.po +++ b/locale/es/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "No Destacar" diff --git a/locale/et_EE/gitlab.po b/locale/et_EE/gitlab.po index cbd55440d7d..56689d244b9 100644 --- a/locale/et_EE/gitlab.po +++ b/locale/et_EE/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/fa_IR/gitlab.po b/locale/fa_IR/gitlab.po index c5e260edfc7..52fa0da2fe2 100644 --- a/locale/fa_IR/gitlab.po +++ b/locale/fa_IR/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po index f6a85b42e75..e94bd85b66a 100644 --- a/locale/fil_PH/gitlab.po +++ b/locale/fil_PH/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po index ec1bc4410bc..c03096687b1 100644 --- a/locale/fr/gitlab.po +++ b/locale/fr/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "Désindexé" msgid "Unstaged %{type}" msgstr "Désindexation de %{type}" -msgid "Unstaged and staged %{type}" -msgstr "%{type} non-indéxés et indexés" - msgid "Unstar" msgstr "Supprimer des favoris" diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d988fcd6dff..52f9231dffa 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -20259,9 +20259,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" @@ -21553,9 +21550,6 @@ msgstr "" msgid "You can create a new one or check them in your Personal Access Tokens settings %{pat_link}" msgstr "" -msgid "You can create files directly in GitLab using one of the following options." -msgstr "" - msgid "You can create new ones at your %{pat_link_start}Personal Access Tokens%{pat_link_end} settings" msgstr "" @@ -21571,6 +21565,9 @@ msgstr "" msgid "You can filter by 'days to merge' by clicking on the columns in the chart." msgstr "" +msgid "You can get started by cloning the repository or start adding files to it with one of the following options." +msgstr "" + msgid "You can invite a new member to %{project_name} or invite another group." msgstr "" diff --git a/locale/gl_ES/gitlab.po b/locale/gl_ES/gitlab.po index c195b59f053..10f3351bf68 100644 --- a/locale/gl_ES/gitlab.po +++ b/locale/gl_ES/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/he_IL/gitlab.po b/locale/he_IL/gitlab.po index f66b860ccbf..5485117f27b 100644 --- a/locale/he_IL/gitlab.po +++ b/locale/he_IL/gitlab.po @@ -20226,9 +20226,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/hi_IN/gitlab.po b/locale/hi_IN/gitlab.po index 34714faeb8a..df702aa71b6 100644 --- a/locale/hi_IN/gitlab.po +++ b/locale/hi_IN/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/hr_HR/gitlab.po b/locale/hr_HR/gitlab.po index 6f11504b6d4..34e04e736c0 100644 --- a/locale/hr_HR/gitlab.po +++ b/locale/hr_HR/gitlab.po @@ -20123,9 +20123,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/hu_HU/gitlab.po b/locale/hu_HU/gitlab.po index 1479fc5dcc2..7eff6234233 100644 --- a/locale/hu_HU/gitlab.po +++ b/locale/hu_HU/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po index 4f7d8501121..37ed84e05c9 100644 --- a/locale/id_ID/gitlab.po +++ b/locale/id_ID/gitlab.po @@ -19917,9 +19917,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po index 3ae19b312f5..04061fbd995 100644 --- a/locale/it/gitlab.po +++ b/locale/it/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "Unstaged" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po index 8455088e6e2..60da219ecdf 100644 --- a/locale/ja/gitlab.po +++ b/locale/ja/gitlab.po @@ -19917,9 +19917,6 @@ msgstr "ステージを取り消し" msgid "Unstaged %{type}" msgstr "ステージを取り消し %{type}" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "スターを外す" diff --git a/locale/ka_GE/gitlab.po b/locale/ka_GE/gitlab.po index fea8c3eee58..6df25e07f22 100644 --- a/locale/ka_GE/gitlab.po +++ b/locale/ka_GE/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po index e15b0917490..16aa0ab358a 100644 --- a/locale/ko/gitlab.po +++ b/locale/ko/gitlab.po @@ -19917,9 +19917,6 @@ msgstr "스테이징 안됨" msgid "Unstaged %{type}" msgstr "%{type} 스테이징 취소" -msgid "Unstaged and staged %{type}" -msgstr "스테이징 취소, 그리고 %{type} 스테이징" - msgid "Unstar" msgstr "별표 제거" diff --git a/locale/ku_TR/gitlab.po b/locale/ku_TR/gitlab.po index a0fd9e8c7f5..0f27e379c58 100644 --- a/locale/ku_TR/gitlab.po +++ b/locale/ku_TR/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/ml_IN/gitlab.po b/locale/ml_IN/gitlab.po index c073b1b257b..12a67356bf3 100644 --- a/locale/ml_IN/gitlab.po +++ b/locale/ml_IN/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/mn_MN/gitlab.po b/locale/mn_MN/gitlab.po index f167dc7072c..45fec0a64ad 100644 --- a/locale/mn_MN/gitlab.po +++ b/locale/mn_MN/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/nb_NO/gitlab.po b/locale/nb_NO/gitlab.po index 6a147fc6363..a7d1bc4b0c1 100644 --- a/locale/nb_NO/gitlab.po +++ b/locale/nb_NO/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po index 55e3d2df9f9..ca5873c98fe 100644 --- a/locale/nl_NL/gitlab.po +++ b/locale/nl_NL/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/pa_IN/gitlab.po b/locale/pa_IN/gitlab.po index ed2b511c66d..04ee1ebc008 100644 --- a/locale/pa_IN/gitlab.po +++ b/locale/pa_IN/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po index dec90aa1adc..b74c006780f 100644 --- a/locale/pl_PL/gitlab.po +++ b/locale/pl_PL/gitlab.po @@ -20226,9 +20226,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po index 8ec714b5ee2..55ff541e69c 100644 --- a/locale/pt_BR/gitlab.po +++ b/locale/pt_BR/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "Fora da lista de commit" msgid "Unstaged %{type}" msgstr "%{type} fora da lista para commit" -msgid "Unstaged and staged %{type}" -msgstr "%{type} dentro e fora da lista para commit" - msgid "Unstar" msgstr "Desmarcar como favorito" diff --git a/locale/pt_PT/gitlab.po b/locale/pt_PT/gitlab.po index 213a84dc9f7..5b22442d85c 100644 --- a/locale/pt_PT/gitlab.po +++ b/locale/pt_PT/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/ro_RO/gitlab.po b/locale/ro_RO/gitlab.po index fa8ec51ab73..413ec40148f 100644 --- a/locale/ro_RO/gitlab.po +++ b/locale/ro_RO/gitlab.po @@ -20123,9 +20123,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po index 0314348e949..9b0fa19f34c 100644 --- a/locale/ru/gitlab.po +++ b/locale/ru/gitlab.po @@ -20226,9 +20226,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "Убрать из избранного" diff --git a/locale/sk_SK/gitlab.po b/locale/sk_SK/gitlab.po index 4f2eab215dd..53beb67f773 100644 --- a/locale/sk_SK/gitlab.po +++ b/locale/sk_SK/gitlab.po @@ -20226,9 +20226,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/sq_AL/gitlab.po b/locale/sq_AL/gitlab.po index a1947bd3429..b11e76c17bb 100644 --- a/locale/sq_AL/gitlab.po +++ b/locale/sq_AL/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/sr_CS/gitlab.po b/locale/sr_CS/gitlab.po index a632fb4133b..b517d1e7072 100644 --- a/locale/sr_CS/gitlab.po +++ b/locale/sr_CS/gitlab.po @@ -20123,9 +20123,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/sr_SP/gitlab.po b/locale/sr_SP/gitlab.po index 7955ce986e2..99def38e91c 100644 --- a/locale/sr_SP/gitlab.po +++ b/locale/sr_SP/gitlab.po @@ -20123,9 +20123,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/sv_SE/gitlab.po b/locale/sv_SE/gitlab.po index f589ee8979d..39297cc5f37 100644 --- a/locale/sv_SE/gitlab.po +++ b/locale/sv_SE/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/sw_KE/gitlab.po b/locale/sw_KE/gitlab.po index 194d07187c7..708d10009b1 100644 --- a/locale/sw_KE/gitlab.po +++ b/locale/sw_KE/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po index c2913b7d9e7..3e3b9df23d7 100644 --- a/locale/tr_TR/gitlab.po +++ b/locale/tr_TR/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "Yıldızı kaldır" diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po index cb6c4de1e03..9f39744dfe0 100644 --- a/locale/uk/gitlab.po +++ b/locale/uk/gitlab.po @@ -20226,9 +20226,6 @@ msgstr "Неіндексовано" msgid "Unstaged %{type}" msgstr "Неіндексовані %{type}" -msgid "Unstaged and staged %{type}" -msgstr "Неіндексовані та проіндексовані %{type}" - msgid "Unstar" msgstr "Видалити із обраних" diff --git a/locale/ur_PK/gitlab.po b/locale/ur_PK/gitlab.po index 52d11fe362e..c93bd7c16ff 100644 --- a/locale/ur_PK/gitlab.po +++ b/locale/ur_PK/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/uz_UZ/gitlab.po b/locale/uz_UZ/gitlab.po index b05679363d7..d0bdb90172e 100644 --- a/locale/uz_UZ/gitlab.po +++ b/locale/uz_UZ/gitlab.po @@ -20020,9 +20020,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/vi_VN/gitlab.po b/locale/vi_VN/gitlab.po index 4e1e5056830..4d0d950f50b 100644 --- a/locale/vi_VN/gitlab.po +++ b/locale/vi_VN/gitlab.po @@ -19917,9 +19917,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po index a07659ed383..7b93e650862 100644 --- a/locale/zh_CN/gitlab.po +++ b/locale/zh_CN/gitlab.po @@ -19917,9 +19917,6 @@ msgstr "未暂存" msgid "Unstaged %{type}" msgstr "未暂存的 %{type}" -msgid "Unstaged and staged %{type}" -msgstr "已暂存和未暂存的 %{type}" - msgid "Unstar" msgstr "取消星标" diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po index a40386c1c90..6053a974db0 100644 --- a/locale/zh_HK/gitlab.po +++ b/locale/zh_HK/gitlab.po @@ -19917,9 +19917,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "取消星標" diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po index 09494baf020..6d2ddbea1d9 100644 --- a/locale/zh_TW/gitlab.po +++ b/locale/zh_TW/gitlab.po @@ -19917,9 +19917,6 @@ msgstr "" msgid "Unstaged %{type}" msgstr "" -msgid "Unstaged and staged %{type}" -msgstr "" - msgid "Unstar" msgstr "" diff --git a/rubocop/cop/include_action_view_context.rb b/rubocop/cop/include_action_view_context.rb deleted file mode 100644 index 52c84a711c9..00000000000 --- a/rubocop/cop/include_action_view_context.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module Cop - # Cop that makes sure workers include `::Gitlab::ActionViewOutput::Context`, not `ActionView::Context`. - class IncludeActionViewContext < RuboCop::Cop::Cop - MSG = 'Include `::Gitlab::ActionViewOutput::Context`, not `ActionView::Context`, for Rails 5.'.freeze - - def_node_matcher :includes_action_view_context?, <<~PATTERN - (send nil? :include (const (const nil? :ActionView) :Context)) - PATTERN - - def on_send(node) - return unless includes_action_view_context?(node) - - add_offense(node.arguments.first, location: :expression) - end - - def autocorrect(node) - lambda do |corrector| - corrector.replace(node.source_range, '::Gitlab::ActionViewOutput::Context') - end - end - end - end -end diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb index 1479dc3384a..d39683c271f 100644 --- a/rubocop/rubocop.rb +++ b/rubocop/rubocop.rb @@ -5,7 +5,6 @@ require_relative 'cop/gitlab/httparty' require_relative 'cop/gitlab/finder_with_find_by' require_relative 'cop/gitlab/union' require_relative 'cop/gitlab/rails_logger' -require_relative 'cop/include_action_view_context' require_relative 'cop/include_sidekiq_worker' require_relative 'cop/safe_params' require_relative 'cop/active_record_association_reload' diff --git a/spec/config/application_spec.rb b/spec/config/application_spec.rb index 01ed81964c3..994cea4c84f 100644 --- a/spec/config/application_spec.rb +++ b/spec/config/application_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' describe Gitlab::Application do # rubocop:disable RSpec/FilePath using RSpec::Parameterized::TableSyntax - FILTERED_PARAM = ActionDispatch::Http::ParameterFilter::FILTERED + FILTERED_PARAM = ActiveSupport::ParameterFilter::FILTERED context 'when parameters are logged' do describe 'rails does not leak confidential parameters' do diff --git a/spec/controllers/concerns/metrics_dashboard_spec.rb b/spec/controllers/concerns/metrics_dashboard_spec.rb index 6ab02057412..466021d6ecd 100644 --- a/spec/controllers/concerns/metrics_dashboard_spec.rb +++ b/spec/controllers/concerns/metrics_dashboard_spec.rb @@ -23,7 +23,7 @@ describe MetricsDashboard do routes.draw { get "metrics_dashboard" => "anonymous#metrics_dashboard" } response = get :metrics_dashboard, format: :json - JSON.parse(response.parsed_body) + response.parsed_body end context 'when no parameters are provided' do diff --git a/spec/controllers/concerns/send_file_upload_spec.rb b/spec/controllers/concerns/send_file_upload_spec.rb index 4110be721ad..3cfb7b5a488 100644 --- a/spec/controllers/concerns/send_file_upload_spec.rb +++ b/spec/controllers/concerns/send_file_upload_spec.rb @@ -59,11 +59,9 @@ describe SendFileUpload do let(:params) { { disposition: 'inline', attachment: filename } } it 'sends a file with inline disposition' do - # Notice the filename= is omitted from the disposition; this is because - # Rails 5 will append this header in send_file expected_params = { filename: 'test.png', - disposition: "inline; filename*=UTF-8''test.png" + disposition: 'inline' } expect(controller).to receive(:send_file).with(uploader.path, expected_params) @@ -76,34 +74,16 @@ describe SendFileUpload do let(:params) { { attachment: filename } } it 'sends a file with content-type of text/plain' do - # Notice the filename= is omitted from the disposition; this is because - # Rails 5 will append this header in send_file expected_params = { content_type: 'text/plain', filename: 'test.js', - disposition: "attachment; filename*=UTF-8''test.js" + disposition: 'attachment' } expect(controller).to receive(:send_file).with(uploader.path, expected_params) subject end - context 'with non-ASCII encoded filename' do - let(:filename) { 'テスト.txt' } - - # Notice the filename= is omitted from the disposition; this is because - # Rails 5 will append this header in send_file - it 'sends content-disposition for non-ASCII encoded filenames' do - expected_params = { - filename: filename, - disposition: "attachment; filename*=UTF-8''%E3%83%86%E3%82%B9%E3%83%88.txt" - } - expect(controller).to receive(:send_file).with(uploader.path, expected_params) - - subject - end - end - context 'with a proxied file in object storage' do before do stub_uploads_object_storage(uploader: uploader_class) diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index 7aaaa363faa..c59983d5138 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -138,14 +138,14 @@ describe Projects::ArtifactsController do let(:filename) { job.artifacts_file.filename } it 'sends the artifacts file' do - # Notice the filename= is omitted from the disposition; this is because - # Rails 5 will append this header in send_file expect(controller).to receive(:send_file) .with( job.artifacts_file.file.path, - hash_including(disposition: %Q(attachment; filename*=UTF-8''#{filename}))).and_call_original + hash_including(disposition: 'attachment', filename: filename)).and_call_original download_artifact + + expect(response.headers['Content-Disposition']).to eq(%Q(attachment; filename="#{filename}"; filename*=UTF-8''#{filename})) end end @@ -170,13 +170,13 @@ describe Projects::ArtifactsController do end it 'sends the codequality report' do - # Notice the filename= is omitted from the disposition; this is because - # Rails 5 will append this header in send_file expect(controller).to receive(:send_file) .with(job.job_artifacts_codequality.file.path, - hash_including(disposition: %Q(attachment; filename*=UTF-8''#{filename}))).and_call_original + hash_including(disposition: 'attachment', filename: filename)).and_call_original download_artifact(file_type: file_type) + + expect(response.headers['Content-Disposition']).to eq(%Q(attachment; filename="#{filename}"; filename*=UTF-8''#{filename})) end end diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb index 6abb58e1aa6..a03fabad2de 100644 --- a/spec/controllers/projects/releases_controller_spec.rb +++ b/spec/controllers/projects/releases_controller_spec.rb @@ -127,13 +127,13 @@ describe Projects::ReleasesController do sign_in(user) end - let!(:release) { create(:release, project: project) } + let(:release) { create(:release, project: project) } let(:tag) { CGI.escape(release.tag) } it_behaves_like 'successful request' context 'when tag name contains slash' do - let!(:release) { create(:release, project: project, tag: 'awesome/v1.0') } + let(:release) { create(:release, project: project, tag: 'awesome/v1.0') } let(:tag) { CGI.escape(release.tag) } it_behaves_like 'successful request' @@ -145,7 +145,6 @@ describe Projects::ReleasesController do end context 'when release does not exist' do - let!(:release) { } let(:tag) { 'non-existent-tag' } it_behaves_like 'not found' @@ -158,6 +157,47 @@ describe Projects::ReleasesController do end end + describe 'GET #show' do + subject do + get :show, params: { namespace_id: project.namespace, project_id: project, tag: tag } + end + + before do + sign_in(user) + end + + let(:release) { create(:release, project: project) } + let(:tag) { CGI.escape(release.tag) } + + it_behaves_like 'successful request' + + context 'when tag name contains slash' do + let(:release) { create(:release, project: project, tag: 'awesome/v1.0') } + let(:tag) { CGI.escape(release.tag) } + + it_behaves_like 'successful request' + + it 'is accesible at a URL encoded path' do + expect(project_release_path(project, release)) + .to eq("/#{project.namespace.path}/#{project.name}/-/releases/awesome%252Fv1.0") + end + end + + context 'when feature flag `release_show_page` is disabled' do + before do + stub_feature_flags(release_show_page: false) + end + + it_behaves_like 'not found' + end + + context 'when release does not exist' do + let(:tag) { 'non-existent-tag' } + + it_behaves_like 'not found' + end + end + describe 'GET #evidence' do let_it_be(:tag_name) { "v1.1.0-evidence" } let!(:release) { create(:release, :with_evidence, project: project, tag: tag_name) } diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 69e2c085659..f42d0560e80 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -649,7 +649,7 @@ describe UploadsController do get :show, params: { model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'dk.png' } expect(response).to have_gitlab_http_status(:ok) - expect(response.header['Content-Disposition']).to end_with 'filename="dk.png"' + expect(response.header['Content-Disposition']).to include('filename="dk.png"') end end diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb index 17754400b91..d12843d7150 100644 --- a/spec/features/merge_request/user_sees_merge_widget_spec.rb +++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb @@ -604,7 +604,7 @@ describe 'Merge request > User sees merge widget', :js do click_button 'addTest' expect(page).to have_content('6.66') - expect(page).to have_content(sample_java_failed_message.gsub!(/\s+/, ' ').strip) + expect(page).to have_content(sample_java_failed_message.gsub(/\s+/, ' ').strip) end end end @@ -649,7 +649,7 @@ describe 'Merge request > User sees merge widget', :js do click_button 'Test#sum when a is 1 and b is 3 returns summary' expect(page).to have_content('2.22') - expect(page).to have_content(sample_rspec_failed_message.gsub!(/\s+/, ' ').strip) + expect(page).to have_content(sample_rspec_failed_message.gsub(/\s+/, ' ').strip) end end end diff --git a/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb b/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb index 254ebfb839a..fb70076fcf1 100644 --- a/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb +++ b/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb @@ -9,7 +9,7 @@ describe "User downloads artifacts" do shared_examples "downloading" do it "downloads the zip" do - expect(page.response_headers["Content-Disposition"]).to eq(%Q{attachment; filename*=UTF-8''#{job.artifacts_file.filename}; filename="#{job.artifacts_file.filename}"}) + expect(page.response_headers['Content-Disposition']).to eq(%Q{attachment; filename="#{job.artifacts_file.filename}"; filename*=UTF-8''#{job.artifacts_file.filename}}) expect(page.response_headers['Content-Transfer-Encoding']).to eq("binary") expect(page.response_headers['Content-Type']).to eq("application/zip") expect(page.source.b).to eq(job.artifacts_file.file.read.b) diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index f9ff076a416..a17793bc6d6 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -346,7 +346,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do artifact_request = requests.find { |req| req.url.match(%r{artifacts/download}) } - expect(artifact_request.response_headers["Content-Disposition"]).to eq(%Q{attachment; filename*=UTF-8''#{job.artifacts_file.filename}; filename="#{job.artifacts_file.filename}"}) + expect(artifact_request.response_headers['Content-Disposition']).to eq(%Q{attachment; filename="#{job.artifacts_file.filename}"; filename*=UTF-8''#{job.artifacts_file.filename}}) expect(artifact_request.response_headers['Content-Transfer-Encoding']).to eq("binary") expect(artifact_request.response_headers['Content-Type']).to eq("image/gif") expect(artifact_request.body).to eq(job.artifacts_file.file.read.b) diff --git a/spec/frontend/vue_shared/components/changed_file_icon_spec.js b/spec/frontend/vue_shared/components/changed_file_icon_spec.js index 5d2aec6734f..8258eb8204c 100644 --- a/spec/frontend/vue_shared/components/changed_file_icon_spec.js +++ b/spec/frontend/vue_shared/components/changed_file_icon_spec.js @@ -3,8 +3,7 @@ import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue'; import Icon from '~/vue_shared/components/icon.vue'; const changedFile = () => ({ changed: true }); -const stagedFile = () => ({ changed: false, staged: true }); -const changedAndStagedFile = () => ({ changed: true, staged: true }); +const stagedFile = () => ({ changed: true, staged: true }); const newFile = () => ({ changed: true, tempFile: true }); const unchangedFile = () => ({ changed: false, tempFile: false, staged: false, deleted: false }); @@ -55,11 +54,10 @@ describe('Changed file icon', () => { }); describe.each` - file | iconName | tooltipText | desc - ${changedFile()} | ${'file-modified'} | ${'Unstaged modification'} | ${'with file changed'} - ${stagedFile()} | ${'file-modified-solid'} | ${'Staged modification'} | ${'with file staged'} - ${changedAndStagedFile()} | ${'file-modified'} | ${'Unstaged and staged modification'} | ${'with file changed and staged'} - ${newFile()} | ${'file-addition'} | ${'Unstaged addition'} | ${'with file new'} + file | iconName | tooltipText | desc + ${changedFile()} | ${'file-modified'} | ${'Unstaged modification'} | ${'with file changed'} + ${stagedFile()} | ${'file-modified-solid'} | ${'Staged modification'} | ${'with file staged'} + ${newFile()} | ${'file-addition'} | ${'Unstaged addition'} | ${'with file new'} `('$desc', ({ file, iconName, tooltipText }) => { beforeEach(() => { factory({ file }); diff --git a/spec/javascripts/editor/editor_lite_spec.js b/spec/javascripts/editor/editor_lite_spec.js new file mode 100644 index 00000000000..154daccf82d --- /dev/null +++ b/spec/javascripts/editor/editor_lite_spec.js @@ -0,0 +1,111 @@ +import { editor as monacoEditor, Uri } from 'monaco-editor'; +import Editor from '~/editor/editor_lite'; + +describe('Base editor', () => { + let editorEl; + let editor; + const blobContent = 'Foo Bar'; + const blobPath = 'test.md'; + const uri = new Uri('gitlab', false, blobPath); + const fakeModel = { foo: 'bar' }; + + beforeEach(() => { + setFixtures('
'); + editorEl = document.getElementById('editor'); + editor = new Editor(); + }); + + afterEach(() => { + editor.dispose(); + editorEl.remove(); + }); + + it('initializes Editor with basic properties', () => { + expect(editor).toBeDefined(); + expect(editor.editorEl).toBe(null); + expect(editor.blobContent).toEqual(''); + expect(editor.blobPath).toEqual(''); + }); + + it('removes `editor-loading` data attribute from the target DOM element', () => { + editor.createInstance({ el: editorEl }); + + expect(editorEl.dataset.editorLoading).toBeUndefined(); + }); + + describe('instance of the Editor', () => { + let modelSpy; + let instanceSpy; + let setModel; + let dispose; + + beforeEach(() => { + setModel = jasmine.createSpy(); + dispose = jasmine.createSpy(); + modelSpy = spyOn(monacoEditor, 'createModel').and.returnValue(fakeModel); + instanceSpy = spyOn(monacoEditor, 'create').and.returnValue({ + setModel, + dispose, + }); + }); + + it('does nothing if no dom element is supplied', () => { + editor.createInstance(); + + expect(editor.editorEl).toBe(null); + expect(editor.blobContent).toEqual(''); + expect(editor.blobPath).toEqual(''); + + expect(modelSpy).not.toHaveBeenCalled(); + expect(instanceSpy).not.toHaveBeenCalled(); + expect(setModel).not.toHaveBeenCalled(); + }); + + it('creates model to be supplied to Monaco editor', () => { + editor.createInstance({ el: editorEl, blobPath, blobContent }); + + expect(modelSpy).toHaveBeenCalledWith(blobContent, undefined, uri); + expect(setModel).toHaveBeenCalledWith(fakeModel); + }); + + it('initializes the instance on a supplied DOM node', () => { + editor.createInstance({ el: editorEl }); + + expect(editor.editorEl).not.toBe(null); + expect(instanceSpy).toHaveBeenCalledWith(editorEl, jasmine.anything()); + }); + }); + + describe('implementation', () => { + beforeEach(() => { + editor.createInstance({ el: editorEl, blobPath, blobContent }); + }); + + afterEach(() => { + editor.model.dispose(); + }); + + it('correctly proxies value from the model', () => { + expect(editor.getValue()).toEqual(blobContent); + }); + + it('is capable of changing the language of the model', () => { + const blobRenamedPath = 'test.js'; + + expect(editor.model.getLanguageIdentifier().language).toEqual('markdown'); + editor.updateModelLanguage(blobRenamedPath); + + expect(editor.model.getLanguageIdentifier().language).toEqual('javascript'); + }); + + it('falls back to plaintext if there is no language associated with an extension', () => { + const blobRenamedPath = 'test.myext'; + const spy = spyOn(console, 'error'); + + editor.updateModelLanguage(blobRenamedPath); + + expect(spy).not.toHaveBeenCalled(); + expect(editor.model.getLanguageIdentifier().language).toEqual('plaintext'); + }); + }); +}); diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 3797e794985..7a8e79fecb1 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -1541,7 +1541,7 @@ describe Gitlab::Database::MigrationHelpers do self.table_name = 'issues' self.inheritance_column = :_type_disabled - belongs_to :project + belongs_to :project, class_name: "::Project" has_internal_id :iid, scope: :project, diff --git a/spec/lib/gitlab/query_limiting/middleware_spec.rb b/spec/lib/gitlab/query_limiting/middleware_spec.rb index f996ea38bb9..f397843df54 100644 --- a/spec/lib/gitlab/query_limiting/middleware_spec.rb +++ b/spec/lib/gitlab/query_limiting/middleware_spec.rb @@ -26,7 +26,7 @@ describe Gitlab::QueryLimiting::Middleware do :controller, action_name: 'show', class: double(:class, name: 'UsersController'), - content_type: 'text/html' + media_type: 'text/html' ) } @@ -39,7 +39,7 @@ describe Gitlab::QueryLimiting::Middleware do :controller, action_name: 'show', class: double(:class, name: 'UsersController'), - content_type: 'application/json' + media_type: 'application/json' ) } diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 1e8598a457c..470b67afe07 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -302,7 +302,11 @@ describe MergeRequest do it 'returns empty requests' do latest_merge_request_diff = merge_request.merge_request_diffs.create - latest_merge_request_diff.merge_request_diff_commits.where(sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0').delete_all + + MergeRequestDiffCommit.where( + merge_request_diff_id: latest_merge_request_diff, + sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0' + ).delete_all expect(by_commit_sha).to be_empty end diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb index 620ef3ff21a..26fa3803651 100644 --- a/spec/presenters/project_presenter_spec.rb +++ b/spec/presenters/project_presenter_spec.rb @@ -297,7 +297,7 @@ describe ProjectPresenter do is_link: false, label: a_string_including("New file"), link: presenter.project_new_blob_path(project, 'master'), - class_modifier: 'success' + class_modifier: 'missing' ) end diff --git a/spec/requests/api/issues/post_projects_issues_spec.rb b/spec/requests/api/issues/post_projects_issues_spec.rb index bbe0683c275..6597a3ab3ba 100644 --- a/spec/requests/api/issues/post_projects_issues_spec.rb +++ b/spec/requests/api/issues/post_projects_issues_spec.rb @@ -389,7 +389,7 @@ describe API::Issues do end before do - expect_next_instance_of(SpamCheckService) do |spam_service| + expect_next_instance_of(Spam::SpamCheckService) do |spam_service| expect(spam_service).to receive_messages(check_for_spam?: true) end expect_next_instance_of(AkismetService) do |akismet_service| diff --git a/spec/requests/api/issues/put_projects_issues_spec.rb b/spec/requests/api/issues/put_projects_issues_spec.rb index 39ac53899da..e6fec2fa1fc 100644 --- a/spec/requests/api/issues/put_projects_issues_spec.rb +++ b/spec/requests/api/issues/put_projects_issues_spec.rb @@ -194,7 +194,7 @@ describe API::Issues do end before do - expect_next_instance_of(SpamCheckService) do |spam_service| + expect_next_instance_of(Spam::SpamCheckService) do |spam_service| expect(spam_service).to receive_messages(check_for_spam?: true) end expect_next_instance_of(AkismetService) do |akismet_service| diff --git a/spec/rubocop/cop/include_action_view_context_spec.rb b/spec/rubocop/cop/include_action_view_context_spec.rb deleted file mode 100644 index c888555b54f..00000000000 --- a/spec/rubocop/cop/include_action_view_context_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -require 'rubocop' -require 'rubocop/rspec/support' - -require_relative '../../../rubocop/cop/include_action_view_context' - -describe RuboCop::Cop::IncludeActionViewContext do - include CopHelper - - subject(:cop) { described_class.new } - - context 'when `ActionView::Context` is included' do - let(:source) { 'include ActionView::Context' } - let(:correct_source) { 'include ::Gitlab::ActionViewOutput::Context' } - - it 'registers an offense' do - inspect_source(source) - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - expect(cop.highlights).to eq(['ActionView::Context']) - end - end - - it 'autocorrects to the right version' do - autocorrected = autocorrect_source(source) - - expect(autocorrected).to eq(correct_source) - end - end - - context 'when `ActionView::Context` is not included' do - it 'registers no offense' do - inspect_source('include Context') - - aggregate_failures do - expect(cop.offenses.size).to eq(0) - end - end - end -end diff --git a/spec/services/akismet_service_spec.rb b/spec/services/akismet_service_spec.rb index 4f1c23b701b..355ff1611a0 100644 --- a/spec/services/akismet_service_spec.rb +++ b/spec/services/akismet_service_spec.rb @@ -19,7 +19,6 @@ describe AkismetService do end shared_examples 'no activity if Akismet is not enabled' do |method_call| - # if the method name is `submit`, it requires an argument, so add it before do stub_application_setting(akismet_enabled: false) end diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index bb68a8dcbbb..3246578c743 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -385,7 +385,7 @@ describe Issues::CreateService do context 'when recaptcha was not verified' do before do - expect_next_instance_of(SpamCheckService) do |spam_service| + expect_next_instance_of(Spam::SpamCheckService) do |spam_service| expect(spam_service).to receive_messages(check_for_spam?: true) end end diff --git a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb index 274d594fd68..20583ff77e9 100644 --- a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb @@ -5,6 +5,8 @@ require 'spec_helper' describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers + STAGES = ::Gitlab::Metrics::Dashboard::Stages + set(:user) { create(:user) } set(:project) { create(:project, :repository) } set(:environment) { create(:environment, project: project) } @@ -16,6 +18,7 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor let(:branch) { "dashboard_new_branch" } let(:dashboard) { 'config/prometheus/common_metrics.yml' } let(:file_name) { 'custom_dashboard.yml' } + let(:file_content_hash) { YAML.safe_load(File.read(dashboard)) } let(:params) do { dashboard: dashboard, @@ -25,17 +28,6 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor } end - let(:dashboard_attrs) do - { - commit_message: commit_message, - branch_name: branch, - start_branch: project.default_branch, - encoding: 'text', - file_path: ".gitlab/dashboards/#{file_name}", - file_content: File.read(dashboard) - } - end - context 'user does not have push right to repository' do it_behaves_like 'misconfigured dashboard service response', :forbidden, %q(You can't commit to this project) end @@ -72,11 +64,12 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor start_branch: project.default_branch, encoding: 'text', file_path: ".gitlab/dashboards/custom_dashboard.yml", - file_content: File.read(dashboard) + file_content: file_content_hash.to_yaml } end it 'strips target file name to safe value', :aggregate_failures do + allow(::Gitlab::Metrics::Dashboard::Processor).to receive(:new).and_return(double(process: file_content_hash)) service_instance = instance_double(::Files::CreateService) expect(::Files::CreateService).to receive(:new).with(project, user, dashboard_attrs).and_return(service_instance) expect(service_instance).to receive(:execute).and_return(status: :success) @@ -86,14 +79,12 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor end context 'valid parameters' do - it 'delegates commit creation to Files::CreateService', :aggregate_failures do - service_instance = instance_double(::Files::CreateService) - expect(::Files::CreateService).to receive(:new).with(project, user, dashboard_attrs).and_return(service_instance) - expect(service_instance).to receive(:execute).and_return(status: :success) - - service_call + before do + allow(::Gitlab::Metrics::Dashboard::Processor).to receive(:new).and_return(double(process: file_content_hash)) end + it_behaves_like 'valid dashboard cloning process', ::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH, [STAGES::CommonMetricsInserter, STAGES::ProjectMetricsInserter, STAGES::Sorter] + context 'selected branch already exists' do let(:branch) { 'existing_branch' } diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 298867f483b..fe31dafdd03 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -47,11 +47,12 @@ describe Projects::TransferService do end end - it 'disk path has moved' do + it 'moves the disk path', :aggregate_failures do old_path = project.repository.disk_path old_full_path = project.repository.full_path transfer_project(project, user, group) + project.reload_repository! expect(project.repository.disk_path).not_to eq(old_path) expect(project.repository.full_path).not_to eq(old_full_path) @@ -298,22 +299,41 @@ describe Projects::TransferService do end context 'when hashed storage in use' do - let(:hashed_project) { create(:project, :repository, namespace: user.namespace) } + let!(:hashed_project) { create(:project, :repository, namespace: user.namespace) } + let!(:old_disk_path) { hashed_project.repository.disk_path } before do group.add_owner(user) end - it 'does not move the directory' do - old_path = hashed_project.repository.disk_path - old_full_path = hashed_project.repository.full_path + it 'does not move the disk path', :aggregate_failures do + new_full_path = "#{group.full_path}/#{hashed_project.path}" transfer_project(hashed_project, user, group) - project.reload + hashed_project.reload_repository! - expect(hashed_project.repository.disk_path).to eq(old_path) - expect(hashed_project.repository.full_path).to eq(old_full_path) - expect(hashed_project.disk_path).to eq(old_path) + expect(hashed_project.repository).to have_attributes( + disk_path: old_disk_path, + full_path: new_full_path + ) + expect(hashed_project.disk_path).to eq(old_disk_path) + end + + it 'does not move the disk path when the transfer fails', :aggregate_failures do + old_full_path = hashed_project.full_path + + expect_next_instance_of(described_class) do |service| + allow(service).to receive(:execute_system_hooks).and_raise('foo') + end + expect { transfer_project(hashed_project, user, group) }.to raise_error('foo') + + hashed_project.reload_repository! + + expect(hashed_project.repository).to have_attributes( + disk_path: old_disk_path, + full_path: old_full_path + ) + expect(hashed_project.disk_path).to eq(old_disk_path) end end diff --git a/spec/services/spam/spam_check_service_spec.rb b/spec/services/spam/spam_check_service_spec.rb new file mode 100644 index 00000000000..5e06d14b8bc --- /dev/null +++ b/spec/services/spam/spam_check_service_spec.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Spam::SpamCheckService do + let(:fake_ip) { '1.2.3.4' } + let(:fake_user_agent) { 'fake-user-agent' } + let(:fake_referrer) { 'fake-http-referrer' } + let(:env) do + { 'action_dispatch.remote_ip' => fake_ip, + 'HTTP_USER_AGENT' => fake_user_agent, + 'HTTP_REFERRER' => fake_referrer } + end + let(:request) { double(:request, env: env) } + + let_it_be(:project) { create(:project, :public) } + let_it_be(:user) { create(:user) } + let_it_be(:issue) { create(:issue, project: project, author: user) } + + before do + issue.spam = false + end + + describe '#initialize' do + subject { described_class.new(spammable: issue, request: request) } + + context 'when the request is nil' do + let(:request) { nil } + + it 'assembles the options with information from the spammable' do + aggregate_failures do + expect(subject.options[:ip_address]).to eq(issue.ip_address) + expect(subject.options[:user_agent]).to eq(issue.user_agent) + expect(subject.options.key?(:referrer)).to be_falsey + end + end + end + + context 'when the request is present' do + let(:request) { double(:request, env: env) } + + it 'assembles the options with information from the spammable' do + aggregate_failures do + expect(subject.options[:ip_address]).to eq(fake_ip) + expect(subject.options[:user_agent]).to eq(fake_user_agent) + expect(subject.options[:referrer]).to eq(fake_referrer) + end + end + end + end + + describe '#execute' do + let(:request) { double(:request, env: env) } + + let_it_be(:existing_spam_log) { create(:spam_log, user: user, recaptcha_verified: false) } + + subject do + described_service = described_class.new(spammable: issue, request: request) + described_service.execute(user_id: user.id, api: nil, recaptcha_verified: recaptcha_verified, spam_log_id: existing_spam_log.id) + end + + context 'when recaptcha was already verified' do + let(:recaptcha_verified) { true } + + it "updates spam log and doesn't check Akismet" do + aggregate_failures do + expect(SpamLog).not_to receive(:create!) + expect(an_instance_of(described_class)).not_to receive(:check) + end + + subject + end + + it 'updates spam log' do + subject + + expect(existing_spam_log.reload.recaptcha_verified).to be_truthy + end + end + + context 'when recaptcha was not verified' do + let(:recaptcha_verified) { false } + + context 'when spammable attributes have not changed' do + before do + issue.closed_at = Time.zone.now + + allow(AkismetService).to receive(:new).and_return(double(spam?: true)) + end + + it 'returns false' do + expect(subject).to be_falsey + end + + it 'does not create a spam log' do + expect { subject } + .not_to change { SpamLog.count } + end + end + + context 'when spammable attributes have changed' do + before do + issue.description = 'SPAM!' + end + + context 'when indicated as spam by akismet' do + before do + allow(AkismetService).to receive(:new).and_return(double(spam?: true)) + end + + context 'when allow_possible_spam feature flag is false' do + before do + stub_feature_flags(allow_possible_spam: false) + end + + it_behaves_like 'akismet spam' + + it 'checks as spam' do + subject + + expect(issue.reload.spam).to be_truthy + end + end + + context 'when allow_possible_spam feature flag is true' do + it_behaves_like 'akismet spam' + + it 'does not check as spam' do + subject + + expect(issue.spam).to be_falsey + end + end + end + + context 'when not indicated as spam by akismet' do + before do + allow(AkismetService).to receive(:new).and_return(double(spam?: false)) + end + + it 'returns false' do + expect(subject).to be_falsey + end + + it 'does not create a spam log' do + expect { subject } + .not_to change { SpamLog.count } + end + end + end + end + end +end diff --git a/spec/services/spam_check_service_spec.rb b/spec/services/spam_check_service_spec.rb deleted file mode 100644 index a58c8d9cfd8..00000000000 --- a/spec/services/spam_check_service_spec.rb +++ /dev/null @@ -1,153 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe SpamCheckService do - let(:fake_ip) { '1.2.3.4' } - let(:fake_user_agent) { 'fake-user-agent' } - let(:fake_referrer) { 'fake-http-referrer' } - let(:env) do - { 'action_dispatch.remote_ip' => fake_ip, - 'HTTP_USER_AGENT' => fake_user_agent, - 'HTTP_REFERRER' => fake_referrer } - end - let(:request) { double(:request, env: env) } - - let_it_be(:project) { create(:project, :public) } - let_it_be(:user) { create(:user) } - let_it_be(:issue) { create(:issue, project: project, author: user) } - - before do - issue.spam = false - end - - describe '#initialize' do - subject { described_class.new(spammable: issue, request: request) } - - context 'when the request is nil' do - let(:request) { nil } - - it 'assembles the options with information from the spammable' do - aggregate_failures do - expect(subject.options[:ip_address]).to eq(issue.ip_address) - expect(subject.options[:user_agent]).to eq(issue.user_agent) - expect(subject.options.key?(:referrer)).to be_falsey - end - end - end - - context 'when the request is present' do - let(:request) { double(:request, env: env) } - - it 'assembles the options with information from the spammable' do - aggregate_failures do - expect(subject.options[:ip_address]).to eq(fake_ip) - expect(subject.options[:user_agent]).to eq(fake_user_agent) - expect(subject.options[:referrer]).to eq(fake_referrer) - end - end - end - end - - describe '#execute' do - let(:request) { double(:request, env: env) } - - let_it_be(:existing_spam_log) { create(:spam_log, user: user, recaptcha_verified: false) } - - subject do - described_service = described_class.new(spammable: issue, request: request) - described_service.execute(user_id: user.id, api: nil, recaptcha_verified: recaptcha_verified, spam_log_id: existing_spam_log.id) - end - - context 'when recaptcha was already verified' do - let(:recaptcha_verified) { true } - - it "updates spam log and doesn't check Akismet" do - aggregate_failures do - expect(SpamLog).not_to receive(:create!) - expect(an_instance_of(described_class)).not_to receive(:check) - end - - subject - end - - it 'updates spam log' do - subject - - expect(existing_spam_log.reload.recaptcha_verified).to be_truthy - end - end - - context 'when recaptcha was not verified' do - let(:recaptcha_verified) { false } - - context 'when spammable attributes have not changed' do - before do - issue.closed_at = Time.zone.now - - allow(AkismetService).to receive(:new).and_return(double(spam?: true)) - end - - it 'returns false' do - expect(subject).to be_falsey - end - - it 'does not create a spam log' do - expect { subject } - .not_to change { SpamLog.count } - end - end - - context 'when spammable attributes have changed' do - before do - issue.description = 'SPAM!' - end - - context 'when indicated as spam by akismet' do - before do - allow(AkismetService).to receive(:new).and_return(double(spam?: true)) - end - - context 'when allow_possible_spam feature flag is false' do - before do - stub_feature_flags(allow_possible_spam: false) - end - - it_behaves_like 'akismet spam' - - it 'checks as spam' do - subject - - expect(issue.reload.spam).to be_truthy - end - end - - context 'when allow_possible_spam feature flag is true' do - it_behaves_like 'akismet spam' - - it 'does not check as spam' do - subject - - expect(issue.spam).to be_falsey - end - end - end - - context 'when not indicated as spam by akismet' do - before do - allow(AkismetService).to receive(:new).and_return(double(spam?: false)) - end - - it 'returns false' do - expect(subject).to be_falsey - end - - it 'does not create a spam log' do - expect { subject } - .not_to change { SpamLog.count } - end - end - end - end - end -end diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb index fd5ad9451f7..4f11f8c6b24 100644 --- a/spec/support/helpers/javascript_fixtures_helpers.rb +++ b/spec/support/helpers/javascript_fixtures_helpers.rb @@ -62,7 +62,7 @@ module JavaScriptFixturesHelpers fixture = response.body fixture.force_encoding("utf-8") - response_mime_type = Mime::Type.lookup(response.content_type) + response_mime_type = Mime::Type.lookup(response.media_type) if response_mime_type.html? doc = Nokogiri::HTML::DocumentFragment.parse(fixture) diff --git a/spec/support/helpers/migrations_helpers.rb b/spec/support/helpers/migrations_helpers.rb index 68f71494771..5eb70f534d8 100644 --- a/spec/support/helpers/migrations_helpers.rb +++ b/spec/support/helpers/migrations_helpers.rb @@ -21,7 +21,7 @@ module MigrationsHelpers end def migration_context - ActiveRecord::MigrationContext.new(migrations_paths) + ActiveRecord::MigrationContext.new(migrations_paths, ActiveRecord::SchemaMigration) end def migrations diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb index 0dc6e851190..6a832ca97d1 100644 --- a/spec/support/helpers/stub_configuration.rb +++ b/spec/support/helpers/stub_configuration.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require 'active_support/core_ext/hash/transform_values' require 'active_support/hash_with_indifferent_access' require 'active_support/dependencies' diff --git a/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb b/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb index b8967bc8df3..fadf428125a 100644 --- a/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb +++ b/spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb @@ -41,13 +41,11 @@ RSpec.shared_examples 'a controller that can serve LFS files' do |options = {}| it 'serves the file' do lfs_uploader = LfsObjectUploader.new(lfs_object) - # Notice the filename= is omitted from the disposition; this is because - # Rails 5 will append this header in send_file expect(controller).to receive(:send_file) .with( File.join(lfs_uploader.root, lfs_uploader.store_dir, lfs_uploader.filename), filename: filename, - disposition: %Q(attachment; filename*=UTF-8''#{filename})) + disposition: 'attachment') subject diff --git a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb index 66a6c073445..1f229d6b783 100644 --- a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb +++ b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb @@ -50,3 +50,38 @@ RSpec.shared_examples 'raises error for users with insufficient permissions' do it_behaves_like 'misconfigured dashboard service response', :unauthorized end end + +RSpec.shared_examples 'valid dashboard cloning process' do |dashboard_template, sequence| + context "dashboard template: #{dashboard_template}" do + let(:dashboard) { dashboard_template } + let(:dashboard_attrs) do + { + commit_message: commit_message, + branch_name: branch, + start_branch: project.default_branch, + encoding: 'text', + file_path: ".gitlab/dashboards/#{file_name}", + file_content: file_content_hash.to_yaml + } + end + + it 'delegates commit creation to Files::CreateService', :aggregate_failures do + service_instance = instance_double(::Files::CreateService) + expect(::Files::CreateService).to receive(:new).with(project, user, dashboard_attrs).and_return(service_instance) + expect(service_instance).to receive(:execute).and_return(status: :success) + + service_call + end + + context 'user has defined custom metrics' do + it 'uses external service to includes them into new file content', :aggregate_failures do + service_instance = double(::Gitlab::Metrics::Dashboard::Processor) + expect(::Gitlab::Metrics::Dashboard::Processor).to receive(:new).with(project, file_content_hash, sequence, {}).and_return(service_instance) + expect(service_instance).to receive(:process).and_return(file_content_hash) + expect(::Files::CreateService).to receive(:new).with(project, user, dashboard_attrs).and_return(double(execute: { status: :success })) + + service_call + end + end + end +end -- cgit v1.2.3