summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md14
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock24
-rw-r--r--Gemfile.rails4.lock18
-rw-r--r--PROCESS.md6
-rw-r--r--app/assets/javascripts/diff_notes/components/jump_to_discussion.js2
-rw-r--r--app/assets/javascripts/diffs/store/getters.js2
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js15
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js11
-rw-r--r--app/assets/javascripts/notebook/cells/output/index.vue2
-rw-r--r--app/assets/javascripts/pages/users/user_overview_block.js5
-rw-r--r--app/assets/javascripts/pages/users/user_tabs.js110
-rw-r--r--app/finders/events_finder.rb2
-rw-r--r--app/finders/group_descendants_finder.rb2
-rw-r--r--app/models/ci/build.rb4
-rw-r--r--app/models/concerns/avatarable.rb2
-rw-r--r--app/models/repository.rb12
-rw-r--r--app/services/issues/update_service.rb13
-rw-r--r--app/services/merge_requests/create_from_issue_service.rb6
-rw-r--r--app/services/quick_actions/interpret_service.rb16
-rw-r--r--app/services/system_note_service.rb8
-rw-r--r--app/services/todos/destroy/entity_leave_service.rb2
-rw-r--r--app/services/todos/destroy/private_features_service.rb6
-rw-r--r--app/views/projects/environments/_external_url.html.haml2
-rw-r--r--app/views/projects/environments/_form.html.haml15
-rw-r--r--app/views/projects/environments/_metrics_button.html.haml4
-rw-r--r--app/views/projects/environments/edit.html.haml4
-rw-r--r--app/views/projects/environments/folder.html.haml2
-rw-r--r--app/views/projects/environments/index.html.haml4
-rw-r--r--app/views/projects/environments/metrics.html.haml2
-rw-r--r--app/views/projects/environments/new.html.haml6
-rw-r--r--app/views/projects/environments/show.html.haml22
-rw-r--r--app/views/projects/environments/terminal.html.haml4
-rw-r--r--app/views/shared/_labels_row.html.haml5
-rw-r--r--app/views/u2f/_authenticate.html.haml10
-rw-r--r--app/views/u2f/_register.html.haml22
-rw-r--r--app/views/users/_overview.html.haml40
-rw-r--r--app/views/users/show.html.haml6
-rw-r--r--changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml5
-rw-r--r--changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml5
-rw-r--r--changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml5
-rw-r--r--changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml5
-rw-r--r--changelogs/unreleased/docs-minor-aws-fixes.yml5
-rw-r--r--changelogs/unreleased/drop-default-value-status-deployments.yml5
-rw-r--r--changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml5
-rw-r--r--changelogs/unreleased/gt-fix-typo-in-notebook-props.yml5
-rw-r--r--changelogs/unreleased/rails5-active-record-class-value.yml5
-rw-r--r--changelogs/unreleased/security-2717-xss-username-autocomplete.yml5
-rw-r--r--changelogs/unreleased/sh-bump-gems-security.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-54189.yml5
-rw-r--r--changelogs/unreleased/zj-improve-gitaly-pb.yml5
-rw-r--r--danger/documentation/Dangerfile27
-rw-r--r--db/migrate/20181112103239_drop_default_value_on_status_deployments.rb14
-rw-r--r--db/schema.rb4
-rw-r--r--doc/ci/yaml/README.md5
-rw-r--r--doc/university/bookclub/booklist.md2
-rw-r--r--doc/university/high-availability/aws/README.md34
-rw-r--r--doc/user/project/clusters/runbooks/img/authorize-jupyter.pngbin0 -> 126425 bytes
-rw-r--r--doc/user/project/clusters/runbooks/img/demo-runbook.pngbin0 -> 132436 bytes
-rw-r--r--doc/user/project/clusters/runbooks/img/gitlab-variables.pngbin0 -> 179611 bytes
-rw-r--r--doc/user/project/clusters/runbooks/img/helm-install.pngbin0 -> 201348 bytes
-rw-r--r--doc/user/project/clusters/runbooks/img/ingress-install.pngbin0 -> 140880 bytes
-rw-r--r--doc/user/project/clusters/runbooks/img/jupyterhub-install.pngbin0 -> 116775 bytes
-rw-r--r--doc/user/project/clusters/runbooks/img/postgres-query.pngbin0 -> 209435 bytes
-rw-r--r--doc/user/project/clusters/runbooks/img/sample-runbook.pngbin0 -> 145728 bytes
-rw-r--r--doc/user/project/clusters/runbooks/index.md94
-rw-r--r--doc/user/project/quick_actions.md1
-rw-r--r--lib/gitlab/auth/saml/auth_hash.rb2
-rw-r--r--lib/gitlab/cache/ci/project_pipeline_status.rb2
-rw-r--r--lib/gitlab/git/blob.rb2
-rw-r--r--lib/gitlab/git/repository.rb6
-rw-r--r--lib/gitlab/gitaly_client.rb125
-rw-r--r--lib/gitlab/hook_data/base_builder.rb2
-rw-r--r--lib/gitlab/hook_data/issuable_builder.rb2
-rw-r--r--lib/gitlab/hook_data/issue_builder.rb2
-rw-r--r--lib/gitlab/hook_data/merge_request_builder.rb2
-rw-r--r--lib/gitlab/hook_data/note_builder.rb2
-rw-r--r--lib/gitlab/hook_data/wiki_page_builder.rb2
-rw-r--r--lib/gitlab/i18n/metadata_entry.rb2
-rw-r--r--lib/gitlab/i18n/po_linter.rb2
-rw-r--r--lib/gitlab/i18n/translation_entry.rb2
-rw-r--r--lib/gitlab/import/logger.rb2
-rw-r--r--lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb2
-rw-r--r--lib/gitlab/import_export/after_export_strategies/download_notification_strategy.rb2
-rw-r--r--lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb2
-rw-r--r--lib/gitlab/import_export/after_export_strategy_builder.rb2
-rw-r--r--lib/gitlab/import_export/attribute_cleaner.rb2
-rw-r--r--lib/gitlab/import_export/attributes_finder.rb2
-rw-r--r--lib/gitlab/import_export/avatar_restorer.rb2
-rw-r--r--lib/gitlab/import_export/avatar_saver.rb2
-rw-r--r--lib/gitlab/import_export/command_line_util.rb2
-rw-r--r--lib/gitlab/import_export/error.rb2
-rw-r--r--lib/gitlab/import_export/file_importer.rb2
-rw-r--r--lib/gitlab/import_export/group_project_object_builder.rb2
-rw-r--r--lib/gitlab/import_export/hash_util.rb2
-rw-r--r--lib/gitlab/import_export/import_export.yml2
-rw-r--r--lib/gitlab/import_export/importer.rb2
-rw-r--r--lib/gitlab/import_export/json_hash_builder.rb2
-rw-r--r--lib/gitlab/import_export/lfs_restorer.rb2
-rw-r--r--lib/gitlab/import_export/lfs_saver.rb2
-rw-r--r--lib/gitlab/import_export/members_mapper.rb2
-rw-r--r--lib/gitlab/import_export/merge_request_parser.rb2
-rw-r--r--lib/gitlab/import_export/project_tree_restorer.rb2
-rw-r--r--lib/gitlab/import_export/project_tree_saver.rb2
-rw-r--r--lib/gitlab/import_export/reader.rb2
-rw-r--r--lib/gitlab/import_export/relation_factory.rb4
-rw-r--r--lib/gitlab/import_export/repo_restorer.rb2
-rw-r--r--lib/gitlab/import_export/repo_saver.rb2
-rw-r--r--lib/gitlab/import_export/saver.rb2
-rw-r--r--lib/gitlab/import_export/shared.rb2
-rw-r--r--lib/gitlab/import_export/statistics_restorer.rb2
-rw-r--r--lib/gitlab/import_export/uploads_manager.rb2
-rw-r--r--lib/gitlab/import_export/uploads_restorer.rb2
-rw-r--r--lib/gitlab/import_export/uploads_saver.rb2
-rw-r--r--lib/gitlab/import_export/version_checker.rb2
-rw-r--r--lib/gitlab/import_export/version_saver.rb2
-rw-r--r--lib/gitlab/import_export/wiki_repo_saver.rb2
-rw-r--r--lib/gitlab/import_export/wiki_restorer.rb2
-rw-r--r--lib/gitlab/kubernetes/config_map.rb2
-rw-r--r--lib/gitlab/kubernetes/helm.rb2
-rw-r--r--lib/gitlab/kubernetes/helm/api.rb2
-rw-r--r--lib/gitlab/kubernetes/helm/base_command.rb2
-rw-r--r--lib/gitlab/kubernetes/helm/client_command.rb2
-rw-r--r--lib/gitlab/kubernetes/helm/init_command.rb2
-rw-r--r--lib/gitlab/kubernetes/helm/install_command.rb2
-rw-r--r--lib/gitlab/kubernetes/helm/pod.rb2
-rw-r--r--lib/gitlab/kubernetes/namespace.rb2
-rw-r--r--lib/gitlab/kubernetes/pod.rb2
-rw-r--r--lib/gitlab/legacy_github_import/base_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/branch_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/client.rb2
-rw-r--r--lib/gitlab/legacy_github_import/comment_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/importer.rb2
-rw-r--r--lib/gitlab/legacy_github_import/issuable_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/issue_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/label_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/milestone_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/project_creator.rb2
-rw-r--r--lib/gitlab/legacy_github_import/pull_request_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/release_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/user_formatter.rb2
-rw-r--r--lib/gitlab/legacy_github_import/wiki_formatter.rb2
-rw-r--r--lib/gitlab/manifest_import/manifest.rb2
-rw-r--r--lib/gitlab/manifest_import/project_creator.rb2
-rw-r--r--lib/gitlab/metrics/background_transaction.rb2
-rw-r--r--lib/gitlab/metrics/delta.rb2
-rw-r--r--lib/gitlab/metrics/influx_db.rb2
-rw-r--r--lib/gitlab/metrics/instrumentation.rb2
-rw-r--r--lib/gitlab/metrics/method_call.rb2
-rw-r--r--lib/gitlab/metrics/methods.rb2
-rw-r--r--lib/gitlab/metrics/methods/metric_options.rb2
-rw-r--r--lib/gitlab/metrics/metric.rb2
-rw-r--r--lib/gitlab/metrics/null_metric.rb2
-rw-r--r--lib/gitlab/metrics/prometheus.rb2
-rw-r--r--lib/gitlab/metrics/rack_middleware.rb2
-rw-r--r--lib/gitlab/metrics/requests_rack_middleware.rb2
-rw-r--r--lib/gitlab/metrics/samplers/base_sampler.rb2
-rw-r--r--lib/gitlab/metrics/samplers/influx_sampler.rb2
-rw-r--r--lib/gitlab/metrics/samplers/ruby_sampler.rb2
-rw-r--r--lib/gitlab/metrics/samplers/unicorn_sampler.rb2
-rw-r--r--lib/gitlab/metrics/sidekiq_metrics_exporter.rb2
-rw-r--r--lib/gitlab/metrics/sidekiq_middleware.rb2
-rw-r--r--lib/gitlab/metrics/subscribers/action_view.rb2
-rw-r--r--lib/gitlab/metrics/subscribers/active_record.rb2
-rw-r--r--lib/gitlab/metrics/subscribers/rails_cache.rb2
-rw-r--r--lib/gitlab/metrics/system.rb2
-rw-r--r--lib/gitlab/metrics/transaction.rb2
-rw-r--r--lib/gitlab/metrics/web_transaction.rb4
-rw-r--r--lib/gitlab/middleware/go.rb2
-rw-r--r--lib/gitlab/middleware/multipart.rb2
-rw-r--r--lib/gitlab/middleware/rails_queue_duration.rb2
-rw-r--r--lib/gitlab/middleware/read_only.rb2
-rw-r--r--lib/gitlab/middleware/read_only/controller.rb2
-rw-r--r--lib/gitlab/middleware/release_env.rb5
-rw-r--r--lib/gitlab/middleware/static.rb2
-rw-r--r--lib/gitlab/repository_cache.rb4
-rw-r--r--locale/gitlab.pot81
-rw-r--r--qa/qa/resource/user.rb11
-rw-r--r--qa/qa/runtime/env.rb16
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb2
-rw-r--r--spec/features/calendar_spec.rb24
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb29
-rw-r--r--spec/features/issues/user_creates_branch_and_merge_request_spec.rb4
-rw-r--r--spec/features/issues/user_uses_quick_actions_spec.rb58
-rw-r--r--spec/features/projects/wiki/user_updates_wiki_page_spec.rb298
-rw-r--r--spec/features/projects/wiki/user_views_wiki_page_spec.rb224
-rw-r--r--spec/features/users/overview_spec.rb8
-rw-r--r--spec/finders/group_descendants_finder_spec.rb7
-rw-r--r--spec/finders/pending_todos_finder_spec.rb2
-rw-r--r--spec/fixtures/authentication/saml2_response.xml56
-rw-r--r--spec/javascripts/lib/utils/text_markdown_spec.js31
-rw-r--r--spec/javascripts/vue_shared/components/expand_button_spec.js2
-rw-r--r--spec/lib/extracts_path_spec.rb26
-rw-r--r--spec/lib/gitlab/auth/saml/auth_hash_spec.rb11
-rw-r--r--spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb14
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb12
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb194
-rw-r--r--spec/lib/gitlab/git/tag_spec.rb30
-rw-r--r--spec/lib/gitlab/git/tree_spec.rb14
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb101
-rw-r--r--spec/lib/gitlab/import_export/project.json10
-rw-r--r--spec/lib/gitlab/import_export/project.light.json22
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb9
-rw-r--r--spec/lib/gitlab/repository_cache_spec.rb22
-rw-r--r--spec/models/merge_request_spec.rb62
-rw-r--r--spec/models/project_wiki_spec.rb250
-rw-r--r--spec/models/repository_spec.rb390
-rw-r--r--spec/models/todo_spec.rb2
-rw-r--r--spec/models/wiki_page_spec.rb280
-rw-r--r--spec/services/merge_requests/create_from_issue_service_spec.rb10
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb53
-rw-r--r--spec/services/system_note_service_spec.rb14
-rw-r--r--spec/support/gitaly.rb16
-rw-r--r--spec/support/helpers/devise_helpers.rb9
214 files changed, 1869 insertions, 1567 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6e5296e231e..54ea014a679 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 11.4.6 (2018-11-18)
+
+### Security (1 change)
+
+- Escape user fullname while rendering autocomplete template to prevent XSS.
+
+
## 11.4.5 (2018-11-04)
### Fixed (4 changes, 1 of them is from the community)
@@ -271,6 +278,13 @@ entry.
- Check frozen string in style builds. (gfyoung)
+## 11.3.10 (2018-11-18)
+
+### Security (1 change)
+
+- Escape user fullname while rendering autocomplete template to prevent XSS.
+
+
## 11.3.9 (2018-10-31)
### Security (1 change)
diff --git a/Gemfile b/Gemfile
index 73c0779e8e5..2c0eb0cbce4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -389,7 +389,7 @@ group :test do
gem 'rails-controller-testing' if rails5? # Rails5 only gem.
gem 'test_after_commit', '~> 1.1' unless rails5? # Remove this gem when migrated to rails 5.0. It's been integrated to rails 5.0.
gem 'sham_rack', '~> 1.3.6'
- gem 'concurrent-ruby', '~> 1.0.5'
+ gem 'concurrent-ruby', '~> 1.1'
gem 'test-prof', '~> 0.2.5'
gem 'rspec_junit_formatter'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 975243f31d5..380f1dbc89f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -128,9 +128,9 @@ GEM
concord (0.1.5)
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
- concurrent-ruby (1.0.5)
- concurrent-ruby-ext (1.0.5)
- concurrent-ruby (= 1.0.5)
+ concurrent-ruby (1.1.3)
+ concurrent-ruby-ext (1.1.3)
+ concurrent-ruby (= 1.1.3)
connection_pool (2.2.2)
crack (0.4.3)
safe_yaml (~> 1.0.0)
@@ -379,7 +379,7 @@ GEM
json (~> 1.8)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
- i18n (1.1.0)
+ i18n (1.1.1)
concurrent-ruby (~> 1.0)
icalendar (2.4.1)
ice_nine (0.11.2)
@@ -444,7 +444,7 @@ GEM
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
- loofah (2.2.2)
+ loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
@@ -453,7 +453,7 @@ GEM
memoist (0.16.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
- method_source (0.9.0)
+ method_source (0.9.2)
mime-types (3.2.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2018.0812)
@@ -475,7 +475,7 @@ GEM
net-ssh (5.0.1)
netrc (0.11.0)
nio4r (2.3.1)
- nokogiri (1.8.4)
+ nokogiri (1.8.5)
mini_portile2 (~> 2.3.0)
nokogumbo (1.5.0)
nokogiri
@@ -603,7 +603,7 @@ GEM
get_process_mem (~> 0.2)
puma (>= 2.7, < 4)
pyu-ruby-sasl (0.0.3.3)
- rack (2.0.5)
+ rack (2.0.6)
rack-accept (0.4.5)
rack (>= 0.4)
rack-attack (4.4.1)
@@ -767,8 +767,8 @@ GEM
ruby-progressbar (1.9.0)
ruby-saml (1.7.2)
nokogiri (>= 1.5.10)
- ruby_parser (3.9.0)
- sexp_processor (~> 4.1)
+ ruby_parser (3.11.0)
+ sexp_processor (~> 4.9)
rubyntlm (0.6.2)
rubypants (0.2.0)
rubyzip (1.2.2)
@@ -808,7 +808,7 @@ GEM
sentry-raven (2.7.2)
faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9)
- sexp_processor (4.9.0)
+ sexp_processor (4.11.0)
sham_rack (1.3.6)
rack
shoulda-matchers (3.1.2)
@@ -967,7 +967,7 @@ DEPENDENCIES
chronic (~> 0.10.2)
chronic_duration (~> 0.10.6)
commonmarker (~> 0.17)
- concurrent-ruby (~> 1.0.5)
+ concurrent-ruby (~> 1.1)
connection_pool (~> 2.0)
creole (~> 0.5.0)
database_cleaner (~> 1.5.0)
diff --git a/Gemfile.rails4.lock b/Gemfile.rails4.lock
index 657975da2a4..ead404c5f27 100644
--- a/Gemfile.rails4.lock
+++ b/Gemfile.rails4.lock
@@ -125,9 +125,9 @@ GEM
concord (0.1.5)
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
- concurrent-ruby (1.0.5)
- concurrent-ruby-ext (1.0.5)
- concurrent-ruby (= 1.0.5)
+ concurrent-ruby (1.1.3)
+ concurrent-ruby-ext (1.1.3)
+ concurrent-ruby (= 1.1.3)
connection_pool (2.2.2)
crack (0.4.3)
safe_yaml (~> 1.0.0)
@@ -441,7 +441,7 @@ GEM
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
- loofah (2.2.2)
+ loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
@@ -471,7 +471,7 @@ GEM
net-ldap (0.16.0)
net-ssh (5.0.1)
netrc (0.11.0)
- nokogiri (1.8.4)
+ nokogiri (1.8.5)
mini_portile2 (~> 2.3.0)
nokogumbo (1.5.0)
nokogiri
@@ -759,8 +759,8 @@ GEM
ruby-progressbar (1.9.0)
ruby-saml (1.7.2)
nokogiri (>= 1.5.10)
- ruby_parser (3.9.0)
- sexp_processor (~> 4.1)
+ ruby_parser (3.11.0)
+ sexp_processor (~> 4.9)
rubyntlm (0.6.2)
rubypants (0.2.0)
rubyzip (1.2.2)
@@ -800,7 +800,7 @@ GEM
sentry-raven (2.7.2)
faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9)
- sexp_processor (4.9.0)
+ sexp_processor (4.11.0)
sham_rack (1.3.6)
rack
shoulda-matchers (3.1.2)
@@ -958,7 +958,7 @@ DEPENDENCIES
chronic (~> 0.10.2)
chronic_duration (~> 0.10.6)
commonmarker (~> 0.17)
- concurrent-ruby (~> 1.0.5)
+ concurrent-ruby (~> 1.1)
connection_pool (~> 2.0)
creole (~> 0.5.0)
database_cleaner (~> 1.5.0)
diff --git a/PROCESS.md b/PROCESS.md
index 5fc2c4cf1df..aadd6a321f0 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -95,6 +95,12 @@ picked into the stable branches) up to the 19th of the month. Such merge
requests should have the ~"feature flag" label assigned, and don't require a
corresponding exception request to be created.
+In order to build the final package and present the feature for self-hosted
+customers, the feature flag should be removed. This should happen before the
+22nd, ideally _at least_ 2 days before. That means MRs with feature
+flags being picked at the 19th would have a quite tight schedule, so picking
+these _earlier_ is preferable.
+
While rare, release managers may decide to reject picking a change into a stable
branch, even when feature flags are used. This might be necessary if the changes
are deemed problematic, too invasive, or there simply isn't enough time to
diff --git a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
index c0c21416275..8542a6e718a 100644
--- a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
+++ b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
@@ -112,7 +112,7 @@ const JumpToDiscussion = Vue.extend({
if (!hasDiscussionsToJumpTo) {
// If there are no discussions to jump to on the current page,
- // switch to the notes tab and jump to the first disucssion there.
+ // switch to the notes tab and jump to the first discussion there.
window.mrTabs.activateTab('show');
activeTab = 'show';
jumpToFirstDiscussion = true;
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 05e32e3c1f1..6a87b712b48 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -23,7 +23,7 @@ export const diffHasAllExpandedDiscussions = (state, getters) => diff => {
};
/**
- * Checks if the diff has all discussions collpased
+ * Checks if the diff has all discussions collapsed
* @param {Object} diff
* @returns {Boolean}
*/
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 00b3d283570..6f8b73564d0 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -151,10 +151,16 @@ class GfmAutoComplete {
// Team Members
$input.atwho({
at: '@',
+ alias: 'users',
displayTpl(value) {
let tmpl = GfmAutoComplete.Loading.template;
- if (value.username != null) {
- tmpl = GfmAutoComplete.Members.template;
+ const { avatarTag, username, title } = value;
+ if (username != null) {
+ tmpl = GfmAutoComplete.Members.templateFunction({
+ avatarTag,
+ username,
+ title,
+ });
}
return tmpl;
},
@@ -565,8 +571,9 @@ GfmAutoComplete.Emoji = {
};
// Team Members
GfmAutoComplete.Members = {
- // eslint-disable-next-line no-template-curly-in-string
- template: '<li>${avatarTag} ${username} <small>${title}</small></li>',
+ templateFunction({ avatarTag, username, title }) {
+ return `<li>${avatarTag} ${username} <small>${_.escape(title)}</small></li>`;
+ },
};
GfmAutoComplete.Labels = {
template:
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index c52cfb806a2..3618c6af7e2 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -39,7 +39,7 @@ function blockTagText(text, textArea, blockTag, selected) {
}
}
-function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
+function moveCursor({ textArea, tag, positionBetweenTags, removedLastNewLine, select }) {
var pos;
if (!textArea.setSelectionRange) {
return;
@@ -51,7 +51,7 @@ function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
return textArea.setSelectionRange(startPosition, endPosition);
}
if (textArea.selectionStart === textArea.selectionEnd) {
- if (wrapped) {
+ if (positionBetweenTags) {
pos = textArea.selectionStart - tag.length;
} else {
pos = textArea.selectionStart;
@@ -67,7 +67,6 @@ function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) {
var textToInsert,
- inserted,
selectedSplit,
startChar,
removedLastNewLine,
@@ -155,7 +154,7 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr
return moveCursor({
textArea,
tag: tag.replace(textPlaceholder, selected),
- wrap,
+ positionBetweenTags: wrap && selected.length === 0,
removedLastNewLine,
select,
});
@@ -171,10 +170,6 @@ function updateText({ textArea, tag, blockTag, wrap, select }) {
return insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select });
}
-function replaceRange(s, start, end, substitute) {
- return s.substring(0, start) + substitute + s.substring(end);
-}
-
export function addMarkdownListeners(form) {
return $('.js-md', form)
.off('click')
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
index d9f8604ed10..bd0bcc0d819 100644
--- a/app/assets/javascripts/notebook/cells/output/index.vue
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -22,7 +22,7 @@ export default {
},
output: {
type: Object,
- requred: true,
+ required: true,
default: () => ({}),
},
},
diff --git a/app/assets/javascripts/pages/users/user_overview_block.js b/app/assets/javascripts/pages/users/user_overview_block.js
index 2ed177be558..eec2b5ca8e5 100644
--- a/app/assets/javascripts/pages/users/user_overview_block.js
+++ b/app/assets/javascripts/pages/users/user_overview_block.js
@@ -10,6 +10,7 @@ export default class UserOverviewBlock {
limit: DEFAULT_LIMIT,
...options.requestParams,
};
+ this.postRenderCallback = options.postRenderCallback;
this.loadData();
}
@@ -43,5 +44,9 @@ export default class UserOverviewBlock {
}
loadingEl.classList.add('hide');
+
+ if (this.postRenderCallback) {
+ this.postRenderCallback.call(this);
+ }
}
}
diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js
index 04bcb16f036..aa537d4a43e 100644
--- a/app/assets/javascripts/pages/users/user_tabs.js
+++ b/app/assets/javascripts/pages/users/user_tabs.js
@@ -2,7 +2,8 @@ import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import Activities from '~/activities';
import { localTimeAgo } from '~/lib/utils/datetime_utility';
-import { __, sprintf } from '~/locale';
+import AjaxCache from '~/lib/utils/ajax_cache';
+import { __ } from '~/locale';
import flash from '~/flash';
import ActivityCalendar from './activity_calendar';
import UserOverviewBlock from './user_overview_block';
@@ -62,23 +63,20 @@ import UserOverviewBlock from './user_overview_block';
* </div>
*/
-const CALENDAR_TEMPLATES = {
- activity: `
- <div class="clearfix calendar">
- <div class="js-contrib-calendar"></div>
- <div class="calendar-hint bottom-right"></div>
- </div>
- `,
- overview: `
- <div class="clearfix calendar">
- <div class="calendar-hint"></div>
- <div class="js-contrib-calendar prepend-top-20"></div>
- </div>
- `,
-};
+const CALENDAR_TEMPLATE = `
+ <div class="clearfix calendar">
+ <div class="js-contrib-calendar"></div>
+ <div class="calendar-hint bottom-right"></div>
+ </div>
+`;
const CALENDAR_PERIOD_6_MONTHS = 6;
const CALENDAR_PERIOD_12_MONTHS = 12;
+/* computation based on
+ * width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
+ * (see activity_calendar.js)
+ */
+const OVERVIEW_CALENDAR_BREAKPOINT = 918;
export default class UserTabs {
constructor({ defaultAction, action, parentEl }) {
@@ -105,6 +103,12 @@ export default class UserTabs {
.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event))
.on('click', '.gl-pagination a', event => this.changeProjectsPage(event));
+
+ window.addEventListener('resize', () => this.onResize());
+ }
+
+ onResize() {
+ this.loadActivityCalendar();
}
changeProjectsPage(e) {
@@ -167,8 +171,6 @@ export default class UserTabs {
return;
}
- this.loadActivityCalendar('activity');
-
// eslint-disable-next-line no-new
new Activities('#activity');
@@ -180,10 +182,10 @@ export default class UserTabs {
return;
}
- this.loadActivityCalendar('overview');
+ this.loadActivityCalendar();
UserTabs.renderMostRecentBlocks('#js-overview .activities-block', {
- requestParams: { limit: 5 },
+ requestParams: { limit: 10 },
});
UserTabs.renderMostRecentBlocks('#js-overview .projects-block', {
requestParams: { limit: 10, skip_pagination: true },
@@ -198,52 +200,39 @@ export default class UserTabs {
container,
url: $(`${container} .overview-content-list`).data('href'),
...options,
+ postRenderCallback: () => localTimeAgo($('.js-timeago', container)),
});
}
- loadActivityCalendar(action) {
- const monthsAgo = action === 'overview' ? CALENDAR_PERIOD_6_MONTHS : CALENDAR_PERIOD_12_MONTHS;
+ loadActivityCalendar() {
const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar');
const calendarPath = $calendarWrap.data('calendarPath');
+
+ AjaxCache.retrieve(calendarPath)
+ .then(data => UserTabs.renderActivityCalendar(data, $calendarWrap))
+ .catch(() => flash(__('There was an error loading users activity calendar.')));
+ }
+
+ static renderActivityCalendar(data, $calendarWrap) {
+ const monthsAgo = UserTabs.getVisibleCalendarPeriod($calendarWrap);
const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath');
const utcOffset = $calendarWrap.data('utcOffset');
- let utcFormatted = 'UTC';
- if (utcOffset !== 0) {
- utcFormatted = `UTC${utcOffset > 0 ? '+' : ''}${utcOffset / 3600}`;
- }
+ const calendarHint = __('Issues, merge requests, pushes and comments.');
- axios
- .get(calendarPath)
- .then(({ data }) => {
- $calendarWrap.html(CALENDAR_TEMPLATES[action]);
-
- let calendarHint = '';
-
- if (action === 'activity') {
- calendarHint = sprintf(
- __(
- 'Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})',
- ),
- { utcFormatted },
- );
- } else if (action === 'overview') {
- calendarHint = __('Issues, merge requests, pushes and comments.');
- }
-
- $calendarWrap.find('.calendar-hint').text(calendarHint);
-
- // eslint-disable-next-line no-new
- new ActivityCalendar(
- '.tab-pane.active .js-contrib-calendar',
- '.tab-pane.active .user-calendar-activities',
- data,
- calendarActivitiesPath,
- utcOffset,
- 0,
- monthsAgo,
- );
- })
- .catch(() => flash(__('There was an error loading users activity calendar.')));
+ $calendarWrap.html(CALENDAR_TEMPLATE);
+
+ $calendarWrap.find('.calendar-hint').text(calendarHint);
+
+ // eslint-disable-next-line no-new
+ new ActivityCalendar(
+ '.tab-pane.active .js-contrib-calendar',
+ '.tab-pane.active .user-calendar-activities',
+ data,
+ calendarActivitiesPath,
+ utcOffset,
+ 0,
+ monthsAgo,
+ );
}
toggleLoading(status) {
@@ -267,4 +256,11 @@ export default class UserTabs {
getCurrentAction() {
return this.$parentEl.find('.nav-links a.active').data('action');
}
+
+ static getVisibleCalendarPeriod($calendarWrap) {
+ const width = $calendarWrap.width();
+ return width < OVERVIEW_CALENDAR_BREAKPOINT
+ ? CALENDAR_PERIOD_6_MONTHS
+ : CALENDAR_PERIOD_12_MONTHS;
+ }
}
diff --git a/app/finders/events_finder.rb b/app/finders/events_finder.rb
index 2e82bda8730..8df01f1dad9 100644
--- a/app/finders/events_finder.rb
+++ b/app/finders/events_finder.rb
@@ -58,7 +58,7 @@ class EventsFinder
def by_target_type(events)
return events unless Event::TARGET_TYPES[params[:target_type]]
- events.where(target_type: Event::TARGET_TYPES[params[:target_type]])
+ events.where(target_type: Event::TARGET_TYPES[params[:target_type]].name)
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/group_descendants_finder.rb b/app/finders/group_descendants_finder.rb
index c96979619fd..a9ce5be13f3 100644
--- a/app/finders/group_descendants_finder.rb
+++ b/app/finders/group_descendants_finder.rb
@@ -178,7 +178,7 @@ class GroupDescendantsFinder
end
def sort
- params.fetch(:sort, 'id_asc')
+ params.fetch(:sort, 'created_desc')
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 9a28e245ebd..d60861dc95f 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -98,7 +98,7 @@ module Ci
scope :matches_tag_ids, -> (tag_ids) do
matcher = ::ActsAsTaggableOn::Tagging
- .where(taggable_type: CommitStatus)
+ .where(taggable_type: CommitStatus.name)
.where(context: 'tags')
.where('taggable_id = ci_builds.id')
.where.not(tag_id: tag_ids).select('1')
@@ -108,7 +108,7 @@ module Ci
scope :with_any_tags, -> do
matcher = ::ActsAsTaggableOn::Tagging
- .where(taggable_type: CommitStatus)
+ .where(taggable_type: CommitStatus.name)
.where(context: 'tags')
.where('taggable_id = ci_builds.id').select('1')
diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb
index 0d5311a9985..b42236c1fa2 100644
--- a/app/models/concerns/avatarable.rb
+++ b/app/models/concerns/avatarable.rb
@@ -86,7 +86,7 @@ module Avatarable
params[:model].upload_paths(params[:identifier])
end
- Upload.where(uploader: AvatarUploader, path: paths).find_each do |upload|
+ Upload.where(uploader: AvatarUploader.name, path: paths).find_each do |upload|
model = model_class.instantiate('id' => upload.model_id)
loader.call({ model: model, identifier: File.basename(upload.path) }, upload)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 6e179f61a7b..fff6d4be275 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1049,11 +1049,19 @@ class Repository
end
def cache
- @cache ||= Gitlab::RepositoryCache.new(self)
+ @cache ||= if is_wiki
+ Gitlab::RepositoryCache.new(self, extra_namespace: 'wiki')
+ else
+ Gitlab::RepositoryCache.new(self)
+ end
end
def request_store_cache
- @request_store_cache ||= Gitlab::RepositoryCache.new(self, backend: Gitlab::SafeRequestStore)
+ @request_store_cache ||= if is_wiki
+ Gitlab::RepositoryCache.new(self, extra_namespace: 'wiki', backend: Gitlab::SafeRequestStore)
+ else
+ Gitlab::RepositoryCache.new(self, backend: Gitlab::SafeRequestStore)
+ end
end
def tags_sorted_by_committed_date
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index fba252b0bae..a1d0cc0e568 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -11,6 +11,12 @@ module Issues
move_issue_to_new_project(issue) || update(issue)
end
+ def update(issue)
+ create_merge_request_from_quick_action
+
+ super
+ end
+
def before_update(issue)
spam_check(issue, current_user)
end
@@ -93,6 +99,13 @@ module Issues
private
+ def create_merge_request_from_quick_action
+ create_merge_request_params = params.delete(:create_merge_request)
+ return unless create_merge_request_params
+
+ MergeRequests::CreateFromIssueService.new(project, current_user, create_merge_request_params).execute
+ end
+
def handle_milestone_change(issue)
return if skip_milestone_email
diff --git a/app/services/merge_requests/create_from_issue_service.rb b/app/services/merge_requests/create_from_issue_service.rb
index 020af0bb950..e69791872cc 100644
--- a/app/services/merge_requests/create_from_issue_service.rb
+++ b/app/services/merge_requests/create_from_issue_service.rb
@@ -19,13 +19,15 @@ module MergeRequests
result = CreateBranchService.new(project, current_user).execute(branch_name, ref)
return result if result[:status] == :error
- SystemNoteService.new_issue_branch(issue, project, current_user, branch_name)
-
new_merge_request = create(merge_request)
if new_merge_request.valid?
+ SystemNoteService.new_merge_request(issue, project, current_user, new_merge_request)
+
success(new_merge_request)
else
+ SystemNoteService.new_issue_branch(issue, project, current_user, branch_name)
+
error(new_merge_request.errors)
end
end
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index 9c81de7e90e..d248b10f41e 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -635,6 +635,22 @@ module QuickActions
@updates[:tag_message] = message
end
+ desc 'Create a merge request.'
+ explanation do |branch_name = nil|
+ branch_text = branch_name ? "branch '#{branch_name}'" : 'a branch'
+ "Creates #{branch_text} and a merge request to resolve this issue"
+ end
+ params "<branch name>"
+ condition do
+ issuable.is_a?(Issue) && current_user.can?(:create_merge_request_in, project) && current_user.can?(:push_code, project)
+ end
+ command :create_merge_request do |branch_name = nil|
+ @updates[:create_merge_request] = {
+ branch_name: branch_name,
+ issue_iid: issuable.iid
+ }
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def extract_users(params)
return [] if params.nil?
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 729bc991294..ec6c306227b 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -407,11 +407,17 @@ module SystemNoteService
def new_issue_branch(issue, project, author, branch)
link = url_helpers.project_compare_url(project, from: project.default_branch, to: branch)
- body = "created branch [`#{branch}`](#{link})"
+ body = "created branch [`#{branch}`](#{link}) to address this issue"
create_note(NoteSummary.new(issue, project, author, body, action: 'branch'))
end
+ def new_merge_request(issue, project, author, merge_request)
+ body = "created merge request #{merge_request.to_reference} to address this issue"
+
+ create_note(NoteSummary.new(issue, project, author, body, action: 'merge'))
+ end
+
# Called when a Mentionable references a Noteable
#
# noteable - Noteable object being referenced
diff --git a/app/services/todos/destroy/entity_leave_service.rb b/app/services/todos/destroy/entity_leave_service.rb
index e8d1bcdd142..ebfb20132d0 100644
--- a/app/services/todos/destroy/entity_leave_service.rb
+++ b/app/services/todos/destroy/entity_leave_service.rb
@@ -45,7 +45,7 @@ module Todos
# rubocop: disable CodeReuse/ActiveRecord
def remove_confidential_issue_todos
Todo.where(
- target_id: confidential_issues.select(:id), target_type: Issue, user_id: user.id
+ target_id: confidential_issues.select(:id), target_type: Issue.name, user_id: user.id
).delete_all
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/services/todos/destroy/private_features_service.rb b/app/services/todos/destroy/private_features_service.rb
index a8c3fe0ef5a..bd49519d694 100644
--- a/app/services/todos/destroy/private_features_service.rb
+++ b/app/services/todos/destroy/private_features_service.rb
@@ -14,9 +14,9 @@ module Todos
def execute
ProjectFeature.where(project_id: project_ids).each do |project_features|
target_types = []
- target_types << Issue if private?(project_features.issues_access_level)
- target_types << MergeRequest if private?(project_features.merge_requests_access_level)
- target_types << Commit if private?(project_features.repository_access_level)
+ target_types << Issue.name if private?(project_features.issues_access_level)
+ target_types << MergeRequest.name if private?(project_features.merge_requests_access_level)
+ target_types << Commit.name if private?(project_features.repository_access_level)
next if target_types.empty?
diff --git a/app/views/projects/environments/_external_url.html.haml b/app/views/projects/environments/_external_url.html.haml
index b3a82d1ef41..82567f88ccc 100644
--- a/app/views/projects/environments/_external_url.html.haml
+++ b/app/views/projects/environments/_external_url.html.haml
@@ -1,4 +1,4 @@
- if environment.external_url && can?(current_user, :read_environment, environment)
= link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url has-tooltip qa-view-deployment', title: s_('Environments|Open live environment') do
= sprite_icon('external-link')
- View deployment
+ = _("View deployment")
diff --git a/app/views/projects/environments/_form.html.haml b/app/views/projects/environments/_form.html.haml
index f942b936037..cbd5c54cecc 100644
--- a/app/views/projects/environments/_form.html.haml
+++ b/app/views/projects/environments/_form.html.haml
@@ -1,22 +1,21 @@
.row.prepend-top-default.append-bottom-default
.col-lg-3
%h4.prepend-top-0
- Environments
+ = _("Environments")
%p
- Environments allow you to track deployments of your application
- = succeed "." do
- = link_to "Read more about environments", help_page_path("ci/environments")
+ - link_to_read_more = link_to(_("Read more about environments"), help_page_path("ci/environments"))
+ = _("Environments allow you to track deployments of your application %{link_to_read_more}.").html_safe % { link_to_read_more: link_to_read_more }
= form_for [@project.namespace.becomes(Namespace), @project, @environment], html: { class: 'col-lg-9' } do |f|
= form_errors(@environment)
.form-group
- = f.label :name, 'Name', class: 'label-bold'
+ = f.label :name, _('Name'), class: 'label-bold'
= f.text_field :name, required: true, class: 'form-control'
.form-group
- = f.label :external_url, 'External URL', class: 'label-bold'
+ = f.label :external_url, _('External URL'), class: 'label-bold'
= f.url_field :external_url, class: 'form-control'
.form-actions
- = f.submit 'Save', class: 'btn btn-success'
- = link_to 'Cancel', project_environments_path(@project), class: 'btn btn-cancel'
+ = f.submit _('Save'), class: 'btn btn-save'
+ = link_to _('Cancel'), project_environments_path(@project), class: 'btn btn-cancel'
diff --git a/app/views/projects/environments/_metrics_button.html.haml b/app/views/projects/environments/_metrics_button.html.haml
index a4b27575095..c4f19ea79e7 100644
--- a/app/views/projects/environments/_metrics_button.html.haml
+++ b/app/views/projects/environments/_metrics_button.html.haml
@@ -2,6 +2,6 @@
- return unless can?(current_user, :read_environment, environment)
-= link_to environment_metrics_path(environment), title: 'See metrics', class: 'btn metrics-button' do
+= link_to environment_metrics_path(environment), title: _('See metrics'), class: 'btn metrics-button' do
= sprite_icon('chart')
- Monitoring
+ = _("Monitoring")
diff --git a/app/views/projects/environments/edit.html.haml b/app/views/projects/environments/edit.html.haml
index d6ff3f729b4..d581bd3aeab 100644
--- a/app/views/projects/environments/edit.html.haml
+++ b/app/views/projects/environments/edit.html.haml
@@ -1,8 +1,8 @@
- @no_container = true
-- page_title "Edit", @environment.name, "Environments"
+- page_title _("Edit"), @environment.name, _("Environments")
%div{ class: container_class }
%h3.page-title
- Edit environment
+ = _('Edit environment')
%hr
= render 'form'
diff --git a/app/views/projects/environments/folder.html.haml b/app/views/projects/environments/folder.html.haml
index 1ac7dab6775..b7e1cf85cb7 100644
--- a/app/views/projects/environments/folder.html.haml
+++ b/app/views/projects/environments/folder.html.haml
@@ -1,5 +1,5 @@
- @no_container = true
-- page_title "Environments"
+- page_title _("Environments")
#environments-folder-list-view{ data: { endpoint: folder_project_environments_path(@project, @folder, format: :json),
"folder-name" => @folder,
diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml
index 7ebe617766f..6c0ad34c486 100644
--- a/app/views/projects/environments/index.html.haml
+++ b/app/views/projects/environments/index.html.haml
@@ -1,6 +1,6 @@
- @no_container = true
-- page_title "Environments"
-- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
+- page_title _("Environments")
+- add_to_breadcrumbs(_("Pipelines"), project_pipelines_path(@project))
#environments-list-view{ data: { environments_data: environments_list_data,
"can-create-deployment" => can?(current_user, :create_deployment, @project).to_s,
diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml
index 4222963a754..7b847a85686 100644
--- a/app/views/projects/environments/metrics.html.haml
+++ b/app/views/projects/environments/metrics.html.haml
@@ -1,5 +1,5 @@
- @no_container = true
-- page_title "Metrics for environment", @environment.name
+- page_title _("Metrics for environment"), @environment.name
.prometheus-container{ class: container_class }
#prometheus-graphs{ data: metrics_data(@project, @environment) }
diff --git a/app/views/projects/environments/new.html.haml b/app/views/projects/environments/new.html.haml
index 62b08e85e22..c1067fdff78 100644
--- a/app/views/projects/environments/new.html.haml
+++ b/app/views/projects/environments/new.html.haml
@@ -1,9 +1,9 @@
- @no_container = true
-- breadcrumb_title "Environments"
-- page_title 'New Environment'
+- breadcrumb_title _("Environments")
+- page_title _("New Environment")
%div{ class: container_class }
%h3.page-title
- New environment
+ = _("New environment")
%hr
= render 'form'
diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml
index 8c5b6e089ea..d59b2d4fb01 100644
--- a/app/views/projects/environments/show.html.haml
+++ b/app/views/projects/environments/show.html.haml
@@ -1,7 +1,7 @@
- @no_container = true
-- add_to_breadcrumbs "Environments", project_environments_path(@project)
+- add_to_breadcrumbs _("Environments"), project_environments_path(@project)
- breadcrumb_title @environment.name
-- page_title "Environments"
+- page_title _("Environments")
%div{ class: container_class }
- if can?(current_user, :stop_environment, @environment)
@@ -10,7 +10,7 @@
.modal-content
.modal-header
%h4.modal-title.d-flex.mw-100
- Stopping
+ = s_("Environments|Stopping")
%span.has-tooltip.text-truncate.ml-1.mr-1.flex-fill{ title: @environment.name, data: { container: '#stop-environment-modal' } }
= @environment.name
?
@@ -40,7 +40,7 @@
= render 'projects/environments/external_url', environment: @environment
= render 'projects/environments/metrics_button', environment: @environment
- if can?(current_user, :update_environment, @environment)
- = link_to 'Edit', edit_project_environment_path(@project, @environment), class: 'btn'
+ = link_to _('Edit'), edit_project_environment_path(@project, @environment), class: 'btn'
- if can?(current_user, :stop_environment, @environment)
= button_tag class: 'btn btn-danger', type: 'button', data: { toggle: 'modal',
target: '#stop-environment-modal' } do
@@ -52,21 +52,19 @@
.empty-state
.text-content
%h4.state-title
- You don't have any deployments right now.
+ = _("You don't have any deployments right now.")
%p.blank-state-text
- Define environments in the deploy stage(s) in
- %code .gitlab-ci.yml
- to track deployments here.
+ = _("Define environments in the deploy stage(s) in <code>.gitlab-ci.yml</code> to track deployments here.").html_safe
.text-center
= link_to _("Read more"), help_page_path("ci/environments"), class: "btn btn-success"
- else
.table-holder
.ci-table.environments{ role: 'grid' }
.gl-responsive-table-row.table-row-header{ role: 'row' }
- .table-section.section-10{ role: 'columnheader' } ID
- .table-section.section-30{ role: 'columnheader' } Commit
- .table-section.section-25{ role: 'columnheader' } Job
- .table-section.section-15{ role: 'columnheader' } Created
+ .table-section.section-10{ role: 'columnheader' }= _('ID')
+ .table-section.section-30{ role: 'columnheader' }= _('Commit')
+ .table-section.section-25{ role: 'columnheader' }= _('Job')
+ .table-section.section-15{ role: 'columnheader' }= _('Created')
= render @deployments
diff --git a/app/views/projects/environments/terminal.html.haml b/app/views/projects/environments/terminal.html.haml
index e40d631a1a1..e837d3d56ac 100644
--- a/app/views/projects/environments/terminal.html.haml
+++ b/app/views/projects/environments/terminal.html.haml
@@ -1,5 +1,5 @@
- @no_container = true
-- page_title "Terminal for environment", @environment.name
+- page_title _("Terminal for environment"), @environment.name
- content_for :page_specific_javascripts do
= stylesheet_link_tag "xterm.css"
@@ -9,7 +9,7 @@
.row
.col-sm-6
%h3.page-title
- Terminal for environment
+ = _("Terminal for environment")
= @environment.name
.col-sm-6
diff --git a/app/views/shared/_labels_row.html.haml b/app/views/shared/_labels_row.html.haml
deleted file mode 100644
index 21b37a7c9ae..00000000000
--- a/app/views/shared/_labels_row.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-- labels.each do |label|
- %span.label-row.btn-group{ role: "group", aria: { label: label.name }, style: "color: #{text_color_for_bg(label.color)}" }
- = link_to_label(label, subject: @project, css_class: 'btn btn-transparent')
- %button.btn.btn-transparent.label-remove.js-label-filter-remove{ type: "button", style: "background-color: #{label.color};", data: { label: label.title } }
- = icon("times")
diff --git a/app/views/u2f/_authenticate.html.haml b/app/views/u2f/_authenticate.html.haml
index 1c788b9a737..979f6862de3 100644
--- a/app/views/u2f/_authenticate.html.haml
+++ b/app/views/u2f/_authenticate.html.haml
@@ -1,18 +1,18 @@
#js-authenticate-u2f
-%a.btn.btn-block.btn-info#js-login-2fa-device{ href: '#' } Sign in via 2FA code
+%a.btn.btn-block.btn-info#js-login-2fa-device{ href: '#' }= _("Sign in via 2FA code")
-# haml-lint:disable InlineJavaScript
%script#js-authenticate-u2f-in-progress{ type: "text/template" }
- %p Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now.
+ %p= _("Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now.")
%script#js-authenticate-u2f-error{ type: "text/template" }
%div
- %p <%= error_message %> (error code: <%= error_code %>)
- %a.btn.btn-block.btn-warning#js-u2f-try-again Try again?
+ %p <%= error_message %> (#{_("error code:")} <%= error_code %>)
+ %a.btn.btn-block.btn-warning#js-u2f-try-again= _("Try again?")
%script#js-authenticate-u2f-authenticated{ type: "text/template" }
%div
- %p We heard back from your U2F device. You have been authenticated.
+ %p= _("We heard back from your U2F device. You have been authenticated.")
= form_tag(new_user_session_path, method: :post, id: 'js-login-u2f-form') do |f|
- resource_params = params[resource_name].presence || params
= hidden_field_tag 'user[remember_me]', resource_params.fetch(:remember_me, 0)
diff --git a/app/views/u2f/_register.html.haml b/app/views/u2f/_register.html.haml
index 39d4d82a77d..f6724f72307 100644
--- a/app/views/u2f/_register.html.haml
+++ b/app/views/u2f/_register.html.haml
@@ -2,39 +2,39 @@
-# haml-lint:disable InlineJavaScript
%script#js-register-u2f-not-supported{ type: "text/template" }
- %p Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer).
+ %p= _("Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer).")
%script#js-register-u2f-setup{ type: "text/template" }
- if current_user.two_factor_otp_enabled?
.row.append-bottom-10
.col-md-4
- %button#js-setup-u2f-device.btn.btn-info.btn-block Set up new U2F device
+ %button#js-setup-u2f-device.btn.btn-info.btn-block= _("Set up new U2F device")
.col-md-8
- %p Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left.
+ %p= _("Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left.")
- else
.row.append-bottom-10
.col-md-4
- %button#js-setup-u2f-device.btn.btn-info.btn-block{ disabled: true } Set up new U2F device
+ %button#js-setup-u2f-device.btn.btn-info.btn-block{ disabled: true }= _("Set up new U2F device")
.col-md-8
- %p.text-warning You need to register a two-factor authentication app before you can set up a U2F device.
+ %p.text-warning= _("You need to register a two-factor authentication app before you can set up a U2F device.")
%script#js-register-u2f-in-progress{ type: "text/template" }
- %p Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now.
+ %p= _("Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now.")
%script#js-register-u2f-error{ type: "text/template" }
%div
%p
- %span <%= error_message %> (error code: <%= error_code %>)
- %a.btn.btn-warning#js-u2f-try-again Try again?
+ %span <%= error_message %> (#{_("error code:")} <%= error_code %>)
+ %a.btn.btn-warning#js-u2f-try-again= _("Try again?")
%script#js-register-u2f-registered{ type: "text/template" }
.row.append-bottom-10
.col-md-12
- %p Your device was successfully set up! Give it a name and register it with the GitLab server.
+ %p= _("Your device was successfully set up! Give it a name and register it with the GitLab server.")
= form_tag(create_u2f_profile_two_factor_auth_path, method: :post) do
.row.append-bottom-10
.col-md-3
- = text_field_tag 'u2f_registration[name]', nil, class: 'form-control', placeholder: "Pick a name"
+ = text_field_tag 'u2f_registration[name]', nil, class: 'form-control', placeholder: _("Pick a name")
.col-md-3
= hidden_field_tag 'u2f_registration[device_response]', nil, class: 'form-control', required: true, id: "js-device-response"
- = submit_tag "Register U2F device", class: "btn btn-success"
+ = submit_tag _("Register U2F device"), class: "btn btn-success"
diff --git a/app/views/users/_overview.html.haml b/app/views/users/_overview.html.haml
index cf525f2bb2d..b5bc1180290 100644
--- a/app/views/users/_overview.html.haml
+++ b/app/views/users/_overview.html.haml
@@ -1,32 +1,30 @@
.row
+ .col-12
+ .calendar-block.prepend-top-default.append-bottom-default
+ .user-calendar.d-none.d-sm-block{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
+ %h4.center.light
+ = spinner nil, true
+ .user-calendar-activities.d-none.d-sm-block
+.row
.col-md-12.col-lg-6
- .calendar-block
- .content-block.hide-bottom-border
- %h4
- = s_('UserProfile|Activity')
- .user-calendar.d-none.d-sm-block.text-left{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
- %h4.center.light
- %i.fa.fa-spinner.fa-spin
- .user-calendar-activities.d-none.d-sm-block
-
- if can?(current_user, :read_cross_project)
.activities-block
- .border-bottom.prepend-top-16
- %h5
- = s_('UserProfile|Recent contributions')
+ .prepend-top-16
+ .d-flex.align-items-center.border-bottom
+ %h4.flex-grow
+ = s_('UserProfile|Activity')
+ = link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_path } }
.center.light.loading
- %i.fa.fa-spinner.fa-spin
- .prepend-top-10
- = link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
+ = spinner nil, true
.col-md-12.col-lg-6
.projects-block
- .border-bottom.prepend-top-16
- %h4
- = s_('UserProfile|Personal projects')
+ .prepend-top-16
+ .d-flex.align-items-center.border-bottom
+ %h4.flex-grow
+ = s_('UserProfile|Personal projects')
+ = link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_projects_path } }
.center.light.loading
- %i.fa.fa-spinner.fa-spin
- .prepend-top-10
- = link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
+ = spinner nil, true
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index d6c8420b744..d11476738e4 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -124,12 +124,6 @@
- if profile_tab?(:activity)
#activity.tab-pane
- .row-content-block.calendar-block.white.second-block.d-none.d-sm-block
- .user-calendar{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
- %h4.center.light
- %i.fa.fa-spinner.fa-spin
- .user-calendar-activities
-
- if can?(current_user, :read_cross_project)
%h4.prepend-top-20
= s_('UserProfile|Most Recent Activity')
diff --git a/changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml b/changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml
new file mode 100644
index 00000000000..e1614ac7669
--- /dev/null
+++ b/changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml
@@ -0,0 +1,5 @@
+---
+title: Creates /create_merge_request quickaction
+merge_request: 22485
+author: Jacopo Beschi @jacopo-beschi
+type: added
diff --git a/changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml b/changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml
new file mode 100644
index 00000000000..65aa9323d2e
--- /dev/null
+++ b/changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml
@@ -0,0 +1,5 @@
+---
+title: UI improvements to user's profile
+merge_request: 22977
+author:
+type: other
diff --git a/changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml b/changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml
new file mode 100644
index 00000000000..d076352a27b
--- /dev/null
+++ b/changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml
@@ -0,0 +1,5 @@
+---
+title: Fix default sorting for subgroups and projects list
+merge_request: 23058
+author: Jacopo Beschi @jacopo-beschi
+type: fixed
diff --git a/changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml b/changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml
new file mode 100644
index 00000000000..28e3fae01a9
--- /dev/null
+++ b/changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml
@@ -0,0 +1,5 @@
+---
+title: Refine cursor positioning in Markdown Editor for wrap tags
+merge_request: 23085
+author: Johann Hubert Sonntagbauer
+type: changed
diff --git a/changelogs/unreleased/docs-minor-aws-fixes.yml b/changelogs/unreleased/docs-minor-aws-fixes.yml
new file mode 100644
index 00000000000..64fa6b12afe
--- /dev/null
+++ b/changelogs/unreleased/docs-minor-aws-fixes.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes to AWS documentation spelling and grammar
+merge_request: 23198
+author: Brendan O'Leary
+type: other
diff --git a/changelogs/unreleased/drop-default-value-status-deployments.yml b/changelogs/unreleased/drop-default-value-status-deployments.yml
new file mode 100644
index 00000000000..fdb826a0507
--- /dev/null
+++ b/changelogs/unreleased/drop-default-value-status-deployments.yml
@@ -0,0 +1,5 @@
+---
+title: Drop default value on status column in deployments table
+merge_request: 22971
+author:
+type: other
diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml
new file mode 100644
index 00000000000..e718d716647
--- /dev/null
+++ b/changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml
@@ -0,0 +1,5 @@
+---
+title: Enable even more frozen string for lib/gitlab
+merge_request:
+author: gfyoung
+type: performance
diff --git a/changelogs/unreleased/gt-fix-typo-in-notebook-props.yml b/changelogs/unreleased/gt-fix-typo-in-notebook-props.yml
new file mode 100644
index 00000000000..60603905a2d
--- /dev/null
+++ b/changelogs/unreleased/gt-fix-typo-in-notebook-props.yml
@@ -0,0 +1,5 @@
+---
+title: Fix typo in notebook props
+merge_request: 23103
+author: George Tsiolis
+type: other
diff --git a/changelogs/unreleased/rails5-active-record-class-value.yml b/changelogs/unreleased/rails5-active-record-class-value.yml
new file mode 100644
index 00000000000..9f9fdf10cd1
--- /dev/null
+++ b/changelogs/unreleased/rails5-active-record-class-value.yml
@@ -0,0 +1,5 @@
+---
+title: 'Rails5: Passing a class as a value in an Active Record query is deprecated'
+merge_request: 23164
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/security-2717-xss-username-autocomplete.yml b/changelogs/unreleased/security-2717-xss-username-autocomplete.yml
new file mode 100644
index 00000000000..d9b1015eeb4
--- /dev/null
+++ b/changelogs/unreleased/security-2717-xss-username-autocomplete.yml
@@ -0,0 +1,5 @@
+---
+title: Escape user fullname while rendering autocomplete template to prevent XSS
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/sh-bump-gems-security.yml b/changelogs/unreleased/sh-bump-gems-security.yml
new file mode 100644
index 00000000000..06489f6f979
--- /dev/null
+++ b/changelogs/unreleased/sh-bump-gems-security.yml
@@ -0,0 +1,5 @@
+---
+title: Bump nokogiri, loofah, and rack gems for security updates
+merge_request: 23204
+author:
+type: security
diff --git a/changelogs/unreleased/sh-fix-issue-54189.yml b/changelogs/unreleased/sh-fix-issue-54189.yml
new file mode 100644
index 00000000000..eee743aa5d9
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-54189.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent templated services from being imported
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/zj-improve-gitaly-pb.yml b/changelogs/unreleased/zj-improve-gitaly-pb.yml
new file mode 100644
index 00000000000..506a0303d8a
--- /dev/null
+++ b/changelogs/unreleased/zj-improve-gitaly-pb.yml
@@ -0,0 +1,5 @@
+---
+title: Show what RPC is called in the performance bar
+merge_request: 23140
+author:
+type: other
diff --git a/danger/documentation/Dangerfile b/danger/documentation/Dangerfile
index 1ee025f0972..87c61d6e90d 100644
--- a/danger/documentation/Dangerfile
+++ b/danger/documentation/Dangerfile
@@ -15,10 +15,10 @@ docs_paths_to_review = docs_paths_requiring_review(helper.all_changed_files)
unless docs_paths_to_review.empty?
message 'This merge request adds or changes files that require a ' \
- 'review from the docs team.'
+ 'review from the Docs team.'
markdown(<<~MARKDOWN)
-## Docs Review
+## Docs review
The following files require a review from the Documentation team:
@@ -32,24 +32,15 @@ the documentation. GitLabbers are also welcome to use the [#docs](https://gitlab
Who to ping [based on DevOps stages](https://about.gitlab.com/handbook/product/categories/#devops-stages):
-| Stage | Tech writer |
-| ------------- | ----------- |
-| ~Create | `@marcia` |
-| ~Configure | `@eread` |
-| ~Distribution | `@axil` |
-| ~Geo | `@eread` |
-| ~Gitaly | `@axil` |
-| ~Gitter | `@axil` |
-| ~Manage | `@eread` |
-| ~Monitoring | `@axil` |
-| ~Packaging | `@axil` |
-| ~Plan | `@mikelewis`|
-| ~Release | `marcia` |
-| ~Secure | `@axil` |
-| ~Verify | `@eread` |
+| Tech writer | Stage(s) |
+| ------------ | ------------------------------------------------------------ |
+| `@marcia` | ~Create ~Release |
+| `@axil` | ~Distribution ~Gitaly ~Gitter ~Monitoring ~Packaging ~Secure |
+| `@eread` | ~Manage ~Configure ~Geo ~Verify |
+| `@mikelewis` | ~Plan |
If you are not sure which category the change falls within, or the change is not
-part of one of these categories, you can mention the whole team with `@gl-docsteam`.
+part of one of these categories, you can mention one of the usernames above.
MARKDOWN
unless gitlab.mr_labels.include?('Documentation')
diff --git a/db/migrate/20181112103239_drop_default_value_on_status_deployments.rb b/db/migrate/20181112103239_drop_default_value_on_status_deployments.rb
new file mode 100644
index 00000000000..a480c15e66b
--- /dev/null
+++ b/db/migrate/20181112103239_drop_default_value_on_status_deployments.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class DropDefaultValueOnStatusDeployments < ActiveRecord::Migration
+ DOWNTIME = false
+ DEPLOYMENT_STATUS_SUCCESS = 2 # Equivalent to Deployment.state_machine.states['success'].value
+
+ def up
+ change_column_default :deployments, :status, nil
+ end
+
+ def down
+ change_column_default :deployments, :status, DEPLOYMENT_STATUS_SUCCESS
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 8e02f43f702..cc47368c530 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20181107054254) do
+ActiveRecord::Schema.define(version: 20181112103239) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -807,7 +807,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do
t.datetime "created_at"
t.datetime "updated_at"
t.string "on_stop"
- t.integer "status", limit: 2, default: 2, null: false
+ t.integer "status", limit: 2, null: false
t.datetime_with_timezone "finished_at"
t.index ["created_at"], name: "index_deployments_on_created_at", using: :btree
t.index ["deployable_type", "deployable_id"], name: "index_deployments_on_deployable_type_and_deployable_id", using: :btree
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index ec709280085..44eec43ef54 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -1682,6 +1682,11 @@ include:
NOTE: **Note:**
The remote file must be publicly accessible through a simple GET request, as we don't support authentication schemas in the remote URL.
+ NOTE: **Note:**
+ In order to include files from another repository inside your local network,
+ you may need to enable the **Allow requests to the local network from hooks and services** checkbox
+ located in the **Settings > Network > Outbound requests** section within the **Admin area**.
+
---
diff --git a/doc/university/bookclub/booklist.md b/doc/university/bookclub/booklist.md
index 26c3851276b..84b1f643b91 100644
--- a/doc/university/bookclub/booklist.md
+++ b/doc/university/bookclub/booklist.md
@@ -10,7 +10,7 @@ List of books and resources, that may be worth reading.
1. **The Humble Programmer**
- Edsger W. Dijkstra, 1972 ([paper](http://dl.acm.org/citation.cfm?id=361591))
+ Edsger W. Dijkstra, 1972 ([paper](https://dl.acm.org/citation.cfm?id=361591))
## Programming
diff --git a/doc/university/high-availability/aws/README.md b/doc/university/high-availability/aws/README.md
index 0a7ce922de1..b21cf27c1d3 100644
--- a/doc/university/high-availability/aws/README.md
+++ b/doc/university/high-availability/aws/README.md
@@ -9,7 +9,7 @@ in [significantly degraded performance](https://gitlab.com/gitlab-org/gitlab-ee/
GitLab on AWS can leverage many of the services that are already
configurable with High Availability. These services have a lot of
-flexibility and are able to adopt to most companies, best of all is the
+flexibility and are able to adapt to most companies, best of all is the
ability to automate both vertical and horizontal scaling.
In this article we'll go through a basic HA setup where we'll start by
@@ -55,9 +55,9 @@ and from the Actions dropdown choose Edit DNS Hostnames and select Yes.
### Subnet
Now let's create some subnets in different Availability Zones. Make sure
-that each subnet is associated the the VPC we just created, that it has
+that each subnet is associated to the VPC we just created, that it has
a distinct VPC and lastly that CIDR blocks don't overlap. This will also
-allow us to enable multi AZ for redundancy.
+allow us to enable multi-AZ for redundancy.
We will create private and public subnets to match load balancers and
RDS instances as well.
@@ -98,7 +98,7 @@ traffic from any destination.
![Subnet Config](img/ig-rt.png)
-Before leaving this screen select the next tab to the rgiht which is
+Before leaving this screen select the next tab to the right which is
Subnet Associations and add our public subnets. If you followed our
naming convention they should be easy to find.
@@ -106,8 +106,8 @@ naming convention they should be easy to find.
## Database with RDS
-For our database server we will use Amazon RDS which offers Multi AZ
-for redundancy. Lets start by creating a subnet group and then we'll
+For our database server we will use Amazon RDS which offers Multi-AZ
+for redundancy. Let's start by creating a subnet group and then we'll
create the actual RDS instance.
### Subnet Group
@@ -122,7 +122,7 @@ the VPC ID dropdown and at the bottom we can add our private subnets.
Select the RDS service from the Database section and create a new
PostgreSQL instance. After choosing between a Production or
Development instance we'll start with the actual configuration. On the
-image bellow we have the settings for this article but note the
+image below we have the settings for this article but note the
following two options which are of particular interest for HA:
1. Multi-AZ-Deployment is recommended as redundancy. Read more at
@@ -133,7 +133,7 @@ IOPS (SSD) is best suited for HA. Read more about it at
![RDS Instance Specs](img/instance_specs.png)
-The rest of the setting on this page request a DB identifier, username
+The rest of the setting on this page request a DB identifier, username,
and a master password. We've chosen to use `gitlab-ha`, `gitlab` and a
very secure password respectively. Keep these in hand for later.
@@ -152,7 +152,7 @@ EC is an in-memory hosted caching solution. Redis maintains its own
persistence and is used for certain types of application.
Let's choose the ElastiCache service in the Database section from our
-AWS console. Now lets create a cache subnet group which will be very
+AWS console. Now let's create a cache subnet group which will be very
similar to the RDS subnet group. Make sure to select our VPC and its
private subnets.
@@ -160,7 +160,7 @@ private subnets.
Now press the Launch a Cache Cluster and choose Redis for our
DB engine. You'll be able to configure details such as replication,
-Multi AZ and node types. The second section will allow us to choose our
+Multi-AZ and node types. The second section will allow us to choose our
subnet and security group and
![Redis Cluster details](img/redis-cluster-det.png)
@@ -274,7 +274,7 @@ username, and password.
gitlab_rails['db_password'] = "mypassword"
gitlab_rails['db_host'] = "<rds-endpoint>"
-Next we only need to configure the Redis section by adding the host and
+Next, we only need to configure the Redis section by adding the host and
uncommenting the port.
@@ -285,7 +285,7 @@ to make the EFS integration easier to manage.
gitlab_rails['redis_host'] = "<redis-endpoint>"
gitlab_rails['redis_port'] = 6379
-Finally run reconfigure, you might find it useful to run a check and
+Finally, run reconfigure. You might find it useful to run a check and
a service status to make sure everything has been set up correctly.
sudo gitlab-ctl reconfigure
@@ -321,10 +321,10 @@ The Load Balancer Health will allow us to indicate where to ping and what
makes up a healthy or unhealthy instance.
We won't add the instance on the next session because we'll destroy it
-momentarily as we'll be using the image we where creating. We will keep
+momentarily as we'll be using the image we were creating. We will keep
the Enable Cross-Zone and Enable Connection Draining active.
-After we finish creating the Load Balancer we can re visit our Security
+After we finish creating the Load Balancer we can revisit our Security
Groups to improve access only through the ELB and any other requirement
you might have.
@@ -363,7 +363,7 @@ After this is launched we are able to start creating our Auto Scaling
Group. Start by giving it a name and assigning it our VPC and private
subnets. We also want to always start with two instances and if you
scroll down to Advanced Details we can choose to receive traffic from ELBs.
-Lets enable that option and select our ELB. We also want to use the ELB's
+Let's enable that option and select our ELB. We also want to use the ELB's
health check.
![Auto scaling](img/auto-scaling-det.png)
@@ -388,9 +388,9 @@ we where aiming for.
After you're done with the policies section have some fun trying to break
instances. You should be able to see how the Auto Scaling Group and the
-EC2 screen start bringing them up again.
+EC2 screen starts bringing them up again.
-High Availability is a very big area, we went mostly through scaling and
+High Availability is a vast area, we went mostly through scaling and
some redundancy options but it might also imply Geographic replication.
There is a lot of ground yet to cover so have a read through these other
resources and feel free to open an issue to request additional material.
diff --git a/doc/user/project/clusters/runbooks/img/authorize-jupyter.png b/doc/user/project/clusters/runbooks/img/authorize-jupyter.png
new file mode 100644
index 00000000000..64f95ed45f0
--- /dev/null
+++ b/doc/user/project/clusters/runbooks/img/authorize-jupyter.png
Binary files differ
diff --git a/doc/user/project/clusters/runbooks/img/demo-runbook.png b/doc/user/project/clusters/runbooks/img/demo-runbook.png
new file mode 100644
index 00000000000..25c9df4126d
--- /dev/null
+++ b/doc/user/project/clusters/runbooks/img/demo-runbook.png
Binary files differ
diff --git a/doc/user/project/clusters/runbooks/img/gitlab-variables.png b/doc/user/project/clusters/runbooks/img/gitlab-variables.png
new file mode 100644
index 00000000000..f76ed21145f
--- /dev/null
+++ b/doc/user/project/clusters/runbooks/img/gitlab-variables.png
Binary files differ
diff --git a/doc/user/project/clusters/runbooks/img/helm-install.png b/doc/user/project/clusters/runbooks/img/helm-install.png
new file mode 100644
index 00000000000..e39094bcbf7
--- /dev/null
+++ b/doc/user/project/clusters/runbooks/img/helm-install.png
Binary files differ
diff --git a/doc/user/project/clusters/runbooks/img/ingress-install.png b/doc/user/project/clusters/runbooks/img/ingress-install.png
new file mode 100644
index 00000000000..093c61f2d0e
--- /dev/null
+++ b/doc/user/project/clusters/runbooks/img/ingress-install.png
Binary files differ
diff --git a/doc/user/project/clusters/runbooks/img/jupyterhub-install.png b/doc/user/project/clusters/runbooks/img/jupyterhub-install.png
new file mode 100644
index 00000000000..2115ec9745b
--- /dev/null
+++ b/doc/user/project/clusters/runbooks/img/jupyterhub-install.png
Binary files differ
diff --git a/doc/user/project/clusters/runbooks/img/postgres-query.png b/doc/user/project/clusters/runbooks/img/postgres-query.png
new file mode 100644
index 00000000000..3880438c97a
--- /dev/null
+++ b/doc/user/project/clusters/runbooks/img/postgres-query.png
Binary files differ
diff --git a/doc/user/project/clusters/runbooks/img/sample-runbook.png b/doc/user/project/clusters/runbooks/img/sample-runbook.png
new file mode 100644
index 00000000000..c12ce8990a4
--- /dev/null
+++ b/doc/user/project/clusters/runbooks/img/sample-runbook.png
Binary files differ
diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md
index 3b81e439119..e1b8dc07b50 100644
--- a/doc/user/project/clusters/runbooks/index.md
+++ b/doc/user/project/clusters/runbooks/index.md
@@ -10,8 +10,8 @@ Historically, runbooks took the form of a decision tree or a detailed
step-by-step guide depending on the condition or system.
Modern implementations have introduced the concept of an "executable
-runbooks", where along with a well define process, operators can execute
-code blocks or database queries against a given environment.
+runbooks", where, along with a well-defined process, operators can execute
+pre-written code blocks or database queries against a given environment.
## Nurtch Executable Runbooks
@@ -45,5 +45,93 @@ To create an executable runbook, you will need:
Nurtch is the company behind the [Rubix library](https://github.com/Nurtch/rubix). Rubix is
an open-source python library that makes it easy to perform common DevOps tasks inside Jupyter Notebooks.
Tasks such as plotting Cloudwatch metrics and rolling your ECS/Kubernetes app are simplified
-down to a couple of lines of code. Check the [Nurtch Documentation](http://docs.nurtch.com/en/latest)
+down to a couple of lines of code. See the [Nurtch Documentation](http://docs.nurtch.com/en/latest)
for more information.
+
+## Configure an executable runbook with GitLab
+
+Follow this step-by-step guide to configure an executable runbook in GitLab using
+the components outlined above and the preloaded demo runbook.
+
+### 1. Add a Kubernetes cluster
+
+Follow the steps outlined in [Adding and creating a new GKE cluster via GitLab](https://docs.gitlab.com/ee/user/project/clusters/#adding-and-creating-a-new-gke-cluster-via-gitlab)
+to add a Kubernetes cluster to your project.
+
+### 2. Install Helm Tiller, Ingress, and JupyterHub
+
+Once the cluster has been provisioned in GKE, click the **Install** button next to the **Helm Tiller** app.
+
+![install helm](img/helm-install.png)
+
+Once Tiller has been installed successfully, click the **Install** button next to the **Ingress** app.
+
+![install ingress](img/ingress-install.png)
+
+Once Ingress has been installed successfully, click the **Install** button next to the **JupyterHub** app.
+
+![install jupyterhub](img/jupyterhub-install.png)
+
+### 3. Login to JupyterHub and start the server
+
+Once JupyterHub has been installed successfully, navigate to the displayed **Jupyter Hostname** URL and click
+**Sign in with GitLab**. Authentication is automatically enabled for any user of the GitLab instance via OAuth2. This
+will redirect to GitLab in order to authorize JupyterHub to use your GitLab account. Click **Authorize**.
+
+![authorize jupyter](img/authorize-jupyter.png)
+
+Once the application has been authorized you will taken back to the JupyterHub application. Click **Start My Server**.
+The server will take a couple of seconds to start.
+
+### 4. Configure access
+
+In order for the runbook to access your GitLab project, you will need to enter a
+[GitLab Access Token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html)
+as well as your Project ID in the **Setup** section of the demo runbook.
+
+Double-click the **DevOps-Runbook-Demo** folder located on the left panel.
+
+![demo runbook](img/demo-runbook.png)
+
+Double-click the "Nurtch-DevOps-Demo.ipynb" runbook.
+
+![sample runbook](img/sample-runbook.png)
+
+The contents on the runbook will be displayed on the right side of the screen. Under the "Setup" section, you will find
+entries for both your `PRIVATE_TOKEN` and your `PROJECT_ID`. Enter both these values, conserving the single quotes as follows:
+
+```sql
+PRIVATE_TOKEN = 'n671WNGecHugsdEDPsyo'
+PROJECT_ID = '1234567'
+```
+
+Update the `VARIABLE_NAME` on the last line of this section to match the name of the variable you are using for your
+access token. In this example our variable name is `PRIVATE_TOKEN`.
+
+```sql
+VARIABLE_VALUE = project.variables.get('PRIVATE_TOKEN').value
+```
+
+### 5. Configure an operation
+
+For this example we'll use the "**Run SQL queries in Notebook**" section in the sample runbook to query
+a postgres database. The first 4 lines of the section define the variables that are required for this query to function.
+
+```sql
+%env DB_USER={project.variables.get('DB_USER').value}
+%env DB_PASSWORD={project.variables.get('DB_PASSWORD').value}
+%env DB_ENDPOINT={project.variables.get('DB_ENDPOINT').value}
+%env DB_NAME={project.variables.get('DB_NAME').value}
+```
+
+Create the matching variables in your project's **Settings >> CI/CD >> Variables**
+
+![gitlab variables](img/gitlab-variables.png)
+
+Back in Jupyter, click the "Run SQL queries in Notebook" heading and the click *Run*. The results will be
+displayed in-line as follows:
+
+![postgres query](img/postgres-query.png)
+
+You can try other operations such as running shell scripts or interacting with a Kubernetes cluster. Visit the
+[Nurtch Documentation](http://docs.nurtch.com/) for more information. \ No newline at end of file
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index 0a4542b71ed..85a03d125dd 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -53,6 +53,7 @@ discussions, and descriptions:
| `/target_branch <Local branch Name>` | Set target branch | | ✓ |
| `/wip` | Toggle the Work In Progress status | | ✓ |
| `/merge` | Merge (when pipeline succeeds) | | ✓ |
+| `/create_merge_request <branch name>` | Create a new merge request starting from the current issue | ✓ | |
## Quick actions for commit messages
diff --git a/lib/gitlab/auth/saml/auth_hash.rb b/lib/gitlab/auth/saml/auth_hash.rb
index 316354fd50c..1af9fa40c3a 100644
--- a/lib/gitlab/auth/saml/auth_hash.rb
+++ b/lib/gitlab/auth/saml/auth_hash.rb
@@ -28,7 +28,7 @@ module Gitlab
end
def extract_authn_context(document)
- REXML::XPath.first(document, "//saml:AuthnStatement/saml:AuthnContext/saml:AuthnContextClassRef/text()").to_s
+ REXML::XPath.first(document, "//*[name()='saml:AuthnStatement' or name()='saml2:AuthnStatement']/*[name()='saml:AuthnContext' or name()='saml2:AuthnContext']/*[name()='saml:AuthnContextClassRef' or name()='saml2:AuthnContextClassRef']/text()").to_s
end
end
end
diff --git a/lib/gitlab/cache/ci/project_pipeline_status.rb b/lib/gitlab/cache/ci/project_pipeline_status.rb
index dfbb83f7bb9..78b0eaac8cd 100644
--- a/lib/gitlab/cache/ci/project_pipeline_status.rb
+++ b/lib/gitlab/cache/ci/project_pipeline_status.rb
@@ -42,7 +42,7 @@ module Gitlab
end
def self.cache_key_for_project(project)
- "#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:projects/#{project.id}/pipeline_status/#{project.commit&.sha}"
+ "#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:project:#{project.id}:pipeline_status:#{project.commit&.sha}"
end
def self.update_for_pipeline(pipeline)
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index 9dd1c484d59..2d25389594e 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-# Gitaly note: JV: seems to be completely migrated (behind feature flags).
-
module Gitlab
module Git
class Blob
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 993955d1a6b..289796ae93b 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -885,12 +885,6 @@ module Gitlab
Gitlab::GitalyClient::ConflictsService.new(self, our_commit_oid, their_commit_oid)
end
- def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block)
- wrapped_gitaly_errors do
- Gitlab::GitalyClient.migrate(method, status: status, &block)
- end
- end
-
def clean_stale_repository_files
wrapped_gitaly_errors do
gitaly_repository_client.cleanup if exists?
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 8b455dc7696..66666b88c15 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -9,11 +9,6 @@ require 'grpc/health/v1/health_services_pb'
module Gitlab
module GitalyClient
include Gitlab::Metrics::Methods
- module MigrationStatus
- DISABLED = 1
- OPT_IN = 2
- OPT_OUT = 3
- end
class TooManyInvocationsError < StandardError
attr_reader :call_site, :invocation_count, :max_call_stack
@@ -31,7 +26,7 @@ module Gitlab
end
end
- SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION'.freeze
+ SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION'
MAXIMUM_GITALY_CALLS = 35
CLIENT_NAME = (Sidekiq.server? ? 'gitlab-sidekiq' : 'gitlab-web').freeze
@@ -43,11 +38,6 @@ module Gitlab
self.query_time = 0
- define_histogram :gitaly_migrate_call_duration_seconds do
- docstring "Gitaly migration call execution timings"
- base_labels gitaly_enabled: nil, feature: nil
- end
-
define_histogram :gitaly_controller_action_duration_seconds do
docstring "Gitaly endpoint histogram by controller and action combination"
base_labels Gitlab::Metrics::Transaction::BASE_LABELS.merge(gitaly_service: nil, rpc: nil)
@@ -126,7 +116,6 @@ module Gitlab
def self.call(storage, service, rpc, request, remote_storage: nil, timeout: nil)
start = Gitlab::Metrics::System.monotonic_time
request_hash = request.is_a?(Google::Protobuf::MessageExts) ? request.to_h : {}
- @current_call_id ||= SecureRandom.uuid
enforce_gitaly_request_limits(:call)
@@ -145,9 +134,7 @@ module Gitlab
current_transaction_labels.merge(gitaly_service: service.to_s, rpc: rpc.to_s),
duration)
- add_call_details(id: @current_call_id, feature: service, duration: duration, request: request_hash)
-
- @current_call_id = nil
+ add_call_details(feature: "#{service}##{rpc}", duration: duration, request: request_hash, rpc: rpc)
end
def self.handle_grpc_unavailable!(ex)
@@ -222,7 +209,7 @@ module Gitlab
result
end
- SERVER_FEATURE_FLAGS = %w[gogit_findcommit].freeze
+ SERVER_FEATURE_FLAGS = %w[].freeze
def self.server_feature_flags
SERVER_FEATURE_FLAGS.map do |f|
@@ -237,82 +224,8 @@ module Gitlab
params['gitaly_token'].presence || Gitlab.config.gitaly['token']
end
- # Evaluates whether a feature toggle is on or off
- def self.feature_enabled?(feature_name, status: MigrationStatus::OPT_IN)
- # Disabled features are always off!
- return false if status == MigrationStatus::DISABLED
-
- feature = Feature.get("gitaly_#{feature_name}")
-
- # If the feature has been set, always evaluate
- if Feature.persisted?(feature)
- if feature.percentage_of_time_value > 0
- # Probabilistically enable this feature
- return Random.rand() * 100 < feature.percentage_of_time_value
- end
-
- return feature.enabled?
- end
-
- # If the feature has not been set, the default depends
- # on it's status
- case status
- when MigrationStatus::OPT_OUT
- true
- when MigrationStatus::OPT_IN
- opt_into_all_features? && !explicit_opt_in_required.include?(feature_name)
- else
- false
- end
- rescue => ex
- # During application startup feature lookups in SQL can fail
- Rails.logger.warn "exception while checking Gitaly feature status for #{feature_name}: #{ex}"
- false
- end
-
- # We have a mechanism to let GitLab automatically opt in to all Gitaly
- # features. We want to be able to exclude some features from automatic
- # opt-in. This function has an override in EE.
- def self.explicit_opt_in_required
- []
- end
-
- # opt_into_all_features? returns true when the current environment
- # is one in which we opt into features automatically
- def self.opt_into_all_features?
- Rails.env.development? || ENV["GITALY_FEATURE_DEFAULT_ON"] == "1"
- end
- private_class_method :opt_into_all_features?
-
- def self.migrate(feature, status: MigrationStatus::OPT_IN)
- # Enforce limits at both the `migrate` and `call` sites to ensure that
- # problems are not hidden by a feature being disabled
- enforce_gitaly_request_limits(:migrate)
-
- is_enabled = feature_enabled?(feature, status: status)
- metric_name = feature.to_s
- metric_name += "_gitaly" if is_enabled
-
- Gitlab::Metrics.measure(metric_name) do
- # Some migrate calls wrap other migrate calls
- allow_n_plus_1_calls do
- feature_stack = Thread.current[:gitaly_feature_stack] ||= []
- feature_stack.unshift(feature)
- begin
- start = Gitlab::Metrics::System.monotonic_time
- @current_call_id = SecureRandom.uuid
- call_details = { id: @current_call_id }
- yield is_enabled
- ensure
- total_time = Gitlab::Metrics::System.monotonic_time - start
- gitaly_migrate_call_duration_seconds.observe({ gitaly_enabled: is_enabled, feature: feature }, total_time)
- feature_stack.shift
- Thread.current[:gitaly_feature_stack] = nil if feature_stack.empty?
-
- add_call_details(call_details.merge(feature: feature, duration: total_time))
- end
- end
- end
+ def self.feature_enabled?(feature_name)
+ Feature.enabled?("gitaly_#{feature_name}")
end
# Ensures that Gitaly is not being abuse through n+1 misuse etc
@@ -368,38 +281,20 @@ module Gitlab
end
private_class_method :decrement_call_count
- # Returns an estimate of the number of Gitaly calls made for this
- # request
+ # Returns the of the number of Gitaly calls made for this request
def self.get_request_count
- return 0 unless Gitlab::SafeRequestStore.active?
-
- gitaly_migrate_count = get_call_count("gitaly_migrate_actual")
- gitaly_call_count = get_call_count("gitaly_call_actual")
-
- # Using the maximum of migrate and call_count will provide an
- # indicator of how many Gitaly calls will be made, even
- # before a feature is enabled. This provides us with a single
- # metric, but not an exact number, but this tradeoff is acceptable
- if gitaly_migrate_count > gitaly_call_count
- gitaly_migrate_count
- else
- gitaly_call_count
- end
+ get_call_count("gitaly_call_actual")
end
def self.reset_counts
return unless Gitlab::SafeRequestStore.active?
- %w[migrate call].each do |call_site|
- Gitlab::SafeRequestStore["gitaly_#{call_site}_actual"] = 0
- Gitlab::SafeRequestStore["gitaly_#{call_site}_permitted"] = 0
- end
+ Gitlab::SafeRequestStore["gitaly_call_actual"] = 0
+ Gitlab::SafeRequestStore["gitaly_call_permitted"] = 0
end
def self.add_call_details(details)
- id = details.delete(:id)
-
- return unless id && Gitlab::SafeRequestStore[:peek_enabled]
+ return unless Gitlab::SafeRequestStore[:peek_enabled]
Gitlab::SafeRequestStore['gitaly_call_details'] ||= {}
Gitlab::SafeRequestStore['gitaly_call_details'][id] ||= {}
diff --git a/lib/gitlab/hook_data/base_builder.rb b/lib/gitlab/hook_data/base_builder.rb
index 1a91301e8be..d54175bce81 100644
--- a/lib/gitlab/hook_data/base_builder.rb
+++ b/lib/gitlab/hook_data/base_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module HookData
class BaseBuilder
diff --git a/lib/gitlab/hook_data/issuable_builder.rb b/lib/gitlab/hook_data/issuable_builder.rb
index 65389835ad7..0803df65632 100644
--- a/lib/gitlab/hook_data/issuable_builder.rb
+++ b/lib/gitlab/hook_data/issuable_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module HookData
class IssuableBuilder < BaseBuilder
diff --git a/lib/gitlab/hook_data/issue_builder.rb b/lib/gitlab/hook_data/issue_builder.rb
index dd63db969f6..c99353b9d49 100644
--- a/lib/gitlab/hook_data/issue_builder.rb
+++ b/lib/gitlab/hook_data/issue_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module HookData
class IssueBuilder < BaseBuilder
diff --git a/lib/gitlab/hook_data/merge_request_builder.rb b/lib/gitlab/hook_data/merge_request_builder.rb
index 3aa6a4f3767..ad38e26e40a 100644
--- a/lib/gitlab/hook_data/merge_request_builder.rb
+++ b/lib/gitlab/hook_data/merge_request_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module HookData
class MergeRequestBuilder < BaseBuilder
diff --git a/lib/gitlab/hook_data/note_builder.rb b/lib/gitlab/hook_data/note_builder.rb
index 81873e345d5..ae30ef6364b 100644
--- a/lib/gitlab/hook_data/note_builder.rb
+++ b/lib/gitlab/hook_data/note_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module HookData
class NoteBuilder < BaseBuilder
diff --git a/lib/gitlab/hook_data/wiki_page_builder.rb b/lib/gitlab/hook_data/wiki_page_builder.rb
index 59c94a61cf2..67f06b1ca46 100644
--- a/lib/gitlab/hook_data/wiki_page_builder.rb
+++ b/lib/gitlab/hook_data/wiki_page_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module HookData
class WikiPageBuilder < BaseBuilder
diff --git a/lib/gitlab/i18n/metadata_entry.rb b/lib/gitlab/i18n/metadata_entry.rb
index 36fc1bcdcb7..3764e379681 100644
--- a/lib/gitlab/i18n/metadata_entry.rb
+++ b/lib/gitlab/i18n/metadata_entry.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module I18n
class MetadataEntry
diff --git a/lib/gitlab/i18n/po_linter.rb b/lib/gitlab/i18n/po_linter.rb
index d8e7269a2c2..644ef8c8589 100644
--- a/lib/gitlab/i18n/po_linter.rb
+++ b/lib/gitlab/i18n/po_linter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module I18n
class PoLinter
diff --git a/lib/gitlab/i18n/translation_entry.rb b/lib/gitlab/i18n/translation_entry.rb
index 54adb98f42d..19c10b2e402 100644
--- a/lib/gitlab/i18n/translation_entry.rb
+++ b/lib/gitlab/i18n/translation_entry.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module I18n
class TranslationEntry
diff --git a/lib/gitlab/import/logger.rb b/lib/gitlab/import/logger.rb
index 8414954d141..ab3e822a4e9 100644
--- a/lib/gitlab/import/logger.rb
+++ b/lib/gitlab/import/logger.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Import
class Logger < ::Gitlab::JsonLogger
diff --git a/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb b/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb
index 7cbf653dd97..d39b6fe5955 100644
--- a/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb
+++ b/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
module AfterExportStrategies
diff --git a/lib/gitlab/import_export/after_export_strategies/download_notification_strategy.rb b/lib/gitlab/import_export/after_export_strategies/download_notification_strategy.rb
index 4371a7eff56..1b391314a74 100644
--- a/lib/gitlab/import_export/after_export_strategies/download_notification_strategy.rb
+++ b/lib/gitlab/import_export/after_export_strategies/download_notification_strategy.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
module AfterExportStrategies
diff --git a/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb b/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb
index 4f29bdcea2c..b30900f7c61 100644
--- a/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb
+++ b/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
module AfterExportStrategies
diff --git a/lib/gitlab/import_export/after_export_strategy_builder.rb b/lib/gitlab/import_export/after_export_strategy_builder.rb
index 7eabcae2380..37394f46a99 100644
--- a/lib/gitlab/import_export/after_export_strategy_builder.rb
+++ b/lib/gitlab/import_export/after_export_strategy_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class AfterExportStrategyBuilder
diff --git a/lib/gitlab/import_export/attribute_cleaner.rb b/lib/gitlab/import_export/attribute_cleaner.rb
index 7c9fc5c15bb..93b37b7bc5f 100644
--- a/lib/gitlab/import_export/attribute_cleaner.rb
+++ b/lib/gitlab/import_export/attribute_cleaner.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class AttributeCleaner
diff --git a/lib/gitlab/import_export/attributes_finder.rb b/lib/gitlab/import_export/attributes_finder.rb
index 0c8fda07294..409243e68a5 100644
--- a/lib/gitlab/import_export/attributes_finder.rb
+++ b/lib/gitlab/import_export/attributes_finder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class AttributesFinder
diff --git a/lib/gitlab/import_export/avatar_restorer.rb b/lib/gitlab/import_export/avatar_restorer.rb
index 17796430811..be1b97bd7a7 100644
--- a/lib/gitlab/import_export/avatar_restorer.rb
+++ b/lib/gitlab/import_export/avatar_restorer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class AvatarRestorer
diff --git a/lib/gitlab/import_export/avatar_saver.rb b/lib/gitlab/import_export/avatar_saver.rb
index 6ffebf83dd2..47ca898c690 100644
--- a/lib/gitlab/import_export/avatar_saver.rb
+++ b/lib/gitlab/import_export/avatar_saver.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class AvatarSaver
diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb
index 3adc44f8044..c9e2a6a78d9 100644
--- a/lib/gitlab/import_export/command_line_util.rb
+++ b/lib/gitlab/import_export/command_line_util.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
module CommandLineUtil
diff --git a/lib/gitlab/import_export/error.rb b/lib/gitlab/import_export/error.rb
index 788eedf2686..454dc778b6b 100644
--- a/lib/gitlab/import_export/error.rb
+++ b/lib/gitlab/import_export/error.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
Error = Class.new(StandardError)
diff --git a/lib/gitlab/import_export/file_importer.rb b/lib/gitlab/import_export/file_importer.rb
index 7fd66b4e244..05432f433e7 100644
--- a/lib/gitlab/import_export/file_importer.rb
+++ b/lib/gitlab/import_export/file_importer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class FileImporter
diff --git a/lib/gitlab/import_export/group_project_object_builder.rb b/lib/gitlab/import_export/group_project_object_builder.rb
index 6c2af770119..1c62591ed5a 100644
--- a/lib/gitlab/import_export/group_project_object_builder.rb
+++ b/lib/gitlab/import_export/group_project_object_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
# Given a class, it finds or creates a new object
diff --git a/lib/gitlab/import_export/hash_util.rb b/lib/gitlab/import_export/hash_util.rb
index d4adeeb3797..b6ce89a973b 100644
--- a/lib/gitlab/import_export/hash_util.rb
+++ b/lib/gitlab/import_export/hash_util.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class HashUtil
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index 9790818ecaf..b40eac3de9a 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -154,6 +154,8 @@ excluded_attributes:
- :encrypted_token_iv
- :encrypted_url
- :encrypted_url_iv
+ services:
+ - :template
methods:
labels:
diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb
index 72d5b9b830c..767f1b5de0e 100644
--- a/lib/gitlab/import_export/importer.rb
+++ b/lib/gitlab/import_export/importer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class Importer
diff --git a/lib/gitlab/import_export/json_hash_builder.rb b/lib/gitlab/import_export/json_hash_builder.rb
index b48f63bcd7e..477499e1688 100644
--- a/lib/gitlab/import_export/json_hash_builder.rb
+++ b/lib/gitlab/import_export/json_hash_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
# Generates a hash that conforms with http://apidock.com/rails/Hash/to_json
diff --git a/lib/gitlab/import_export/lfs_restorer.rb b/lib/gitlab/import_export/lfs_restorer.rb
index b28c3c161b7..345c7880e30 100644
--- a/lib/gitlab/import_export/lfs_restorer.rb
+++ b/lib/gitlab/import_export/lfs_restorer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class LfsRestorer
diff --git a/lib/gitlab/import_export/lfs_saver.rb b/lib/gitlab/import_export/lfs_saver.rb
index 29410e2331c..954f6f00078 100644
--- a/lib/gitlab/import_export/lfs_saver.rb
+++ b/lib/gitlab/import_export/lfs_saver.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class LfsSaver
diff --git a/lib/gitlab/import_export/members_mapper.rb b/lib/gitlab/import_export/members_mapper.rb
index bcbaf00e11b..6be95a16513 100644
--- a/lib/gitlab/import_export/members_mapper.rb
+++ b/lib/gitlab/import_export/members_mapper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class MembersMapper
diff --git a/lib/gitlab/import_export/merge_request_parser.rb b/lib/gitlab/import_export/merge_request_parser.rb
index 62a1833b39c..040a70d6775 100644
--- a/lib/gitlab/import_export/merge_request_parser.rb
+++ b/lib/gitlab/import_export/merge_request_parser.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class MergeRequestParser
diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb
index 99581eb0416..8cd4efd91cc 100644
--- a/lib/gitlab/import_export/project_tree_restorer.rb
+++ b/lib/gitlab/import_export/project_tree_restorer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class ProjectTreeRestorer
diff --git a/lib/gitlab/import_export/project_tree_saver.rb b/lib/gitlab/import_export/project_tree_saver.rb
index 5510c0b8b2f..29f2dc80813 100644
--- a/lib/gitlab/import_export/project_tree_saver.rb
+++ b/lib/gitlab/import_export/project_tree_saver.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class ProjectTreeSaver
diff --git a/lib/gitlab/import_export/reader.rb b/lib/gitlab/import_export/reader.rb
index e621c40fc7a..bc0d18e03fa 100644
--- a/lib/gitlab/import_export/reader.rb
+++ b/lib/gitlab/import_export/reader.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class Reader
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index 2486b1e4921..097c7653754 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class RelationFactory
@@ -211,7 +213,7 @@ module Gitlab
def update_note_for_missing_author(author_name)
@relation_hash['note'] = '*Blank note*' if @relation_hash['note'].blank?
- @relation_hash['note'] += missing_author_note(@relation_hash['updated_at'], author_name)
+ @relation_hash['note'] = "#{@relation_hash['note']}#{missing_author_note(@relation_hash['updated_at'], author_name)}"
end
def admin_user?
diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb
index 5a9bbceac67..921a06b4023 100644
--- a/lib/gitlab/import_export/repo_restorer.rb
+++ b/lib/gitlab/import_export/repo_restorer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class RepoRestorer
diff --git a/lib/gitlab/import_export/repo_saver.rb b/lib/gitlab/import_export/repo_saver.rb
index 0c224bd1971..a60618dfcec 100644
--- a/lib/gitlab/import_export/repo_saver.rb
+++ b/lib/gitlab/import_export/repo_saver.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class RepoSaver
diff --git a/lib/gitlab/import_export/saver.rb b/lib/gitlab/import_export/saver.rb
index 59a74083395..72f575db095 100644
--- a/lib/gitlab/import_export/saver.rb
+++ b/lib/gitlab/import_export/saver.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class Saver
diff --git a/lib/gitlab/import_export/shared.rb b/lib/gitlab/import_export/shared.rb
index 6d7c36ce38b..c13e6c1d83b 100644
--- a/lib/gitlab/import_export/shared.rb
+++ b/lib/gitlab/import_export/shared.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class Shared
diff --git a/lib/gitlab/import_export/statistics_restorer.rb b/lib/gitlab/import_export/statistics_restorer.rb
index bcdd9c12c85..3fafb01c37c 100644
--- a/lib/gitlab/import_export/statistics_restorer.rb
+++ b/lib/gitlab/import_export/statistics_restorer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class StatisticsRestorer
diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb
index 8511319cb1c..474e9d45566 100644
--- a/lib/gitlab/import_export/uploads_manager.rb
+++ b/lib/gitlab/import_export/uploads_manager.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class UploadsManager
diff --git a/lib/gitlab/import_export/uploads_restorer.rb b/lib/gitlab/import_export/uploads_restorer.rb
index b4313ff4cb4..5f422dcbefa 100644
--- a/lib/gitlab/import_export/uploads_restorer.rb
+++ b/lib/gitlab/import_export/uploads_restorer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class UploadsRestorer < UploadsSaver
diff --git a/lib/gitlab/import_export/uploads_saver.rb b/lib/gitlab/import_export/uploads_saver.rb
index 0275f686c5e..be1066c30b2 100644
--- a/lib/gitlab/import_export/uploads_saver.rb
+++ b/lib/gitlab/import_export/uploads_saver.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class UploadsSaver
diff --git a/lib/gitlab/import_export/version_checker.rb b/lib/gitlab/import_export/version_checker.rb
index bd3c3ee3b2f..6d978d00ea5 100644
--- a/lib/gitlab/import_export/version_checker.rb
+++ b/lib/gitlab/import_export/version_checker.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class VersionChecker
diff --git a/lib/gitlab/import_export/version_saver.rb b/lib/gitlab/import_export/version_saver.rb
index 7cf88298642..8230c0f1e77 100644
--- a/lib/gitlab/import_export/version_saver.rb
+++ b/lib/gitlab/import_export/version_saver.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class VersionSaver
diff --git a/lib/gitlab/import_export/wiki_repo_saver.rb b/lib/gitlab/import_export/wiki_repo_saver.rb
index 2fd62c0fc7b..7303bcf61a4 100644
--- a/lib/gitlab/import_export/wiki_repo_saver.rb
+++ b/lib/gitlab/import_export/wiki_repo_saver.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class WikiRepoSaver < RepoSaver
diff --git a/lib/gitlab/import_export/wiki_restorer.rb b/lib/gitlab/import_export/wiki_restorer.rb
index f33bfb332ab..28b5e7449cd 100644
--- a/lib/gitlab/import_export/wiki_restorer.rb
+++ b/lib/gitlab/import_export/wiki_restorer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ImportExport
class WikiRestorer < RepoRestorer
diff --git a/lib/gitlab/kubernetes/config_map.rb b/lib/gitlab/kubernetes/config_map.rb
index 9e55dae137c..0bcaaa03974 100644
--- a/lib/gitlab/kubernetes/config_map.rb
+++ b/lib/gitlab/kubernetes/config_map.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
class ConfigMap
diff --git a/lib/gitlab/kubernetes/helm.rb b/lib/gitlab/kubernetes/helm.rb
index 5a22b5e3364..03d38ec78fd 100644
--- a/lib/gitlab/kubernetes/helm.rb
+++ b/lib/gitlab/kubernetes/helm.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
module Helm
diff --git a/lib/gitlab/kubernetes/helm/api.rb b/lib/gitlab/kubernetes/helm/api.rb
index 7c026ac9e68..fd3d187cbc3 100644
--- a/lib/gitlab/kubernetes/helm/api.rb
+++ b/lib/gitlab/kubernetes/helm/api.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
module Helm
diff --git a/lib/gitlab/kubernetes/helm/base_command.rb b/lib/gitlab/kubernetes/helm/base_command.rb
index f2ce24fefa1..2bcb428b25d 100644
--- a/lib/gitlab/kubernetes/helm/base_command.rb
+++ b/lib/gitlab/kubernetes/helm/base_command.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
module Helm
diff --git a/lib/gitlab/kubernetes/helm/client_command.rb b/lib/gitlab/kubernetes/helm/client_command.rb
index 72bafc07bf0..9940272a8bf 100644
--- a/lib/gitlab/kubernetes/helm/client_command.rb
+++ b/lib/gitlab/kubernetes/helm/client_command.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
module Helm
diff --git a/lib/gitlab/kubernetes/helm/init_command.rb b/lib/gitlab/kubernetes/helm/init_command.rb
index 6691080deca..88ed8572ffc 100644
--- a/lib/gitlab/kubernetes/helm/init_command.rb
+++ b/lib/gitlab/kubernetes/helm/init_command.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
module Helm
diff --git a/lib/gitlab/kubernetes/helm/install_command.rb b/lib/gitlab/kubernetes/helm/install_command.rb
index 52700b5dc09..961485005f7 100644
--- a/lib/gitlab/kubernetes/helm/install_command.rb
+++ b/lib/gitlab/kubernetes/helm/install_command.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
module Helm
diff --git a/lib/gitlab/kubernetes/helm/pod.rb b/lib/gitlab/kubernetes/helm/pod.rb
index e9c621d96f0..75484f80070 100644
--- a/lib/gitlab/kubernetes/helm/pod.rb
+++ b/lib/gitlab/kubernetes/helm/pod.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
module Helm
diff --git a/lib/gitlab/kubernetes/namespace.rb b/lib/gitlab/kubernetes/namespace.rb
index 783c8a24741..919f19c86d7 100644
--- a/lib/gitlab/kubernetes/namespace.rb
+++ b/lib/gitlab/kubernetes/namespace.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
class Namespace
diff --git a/lib/gitlab/kubernetes/pod.rb b/lib/gitlab/kubernetes/pod.rb
index f3842cdf762..81317e532b2 100644
--- a/lib/gitlab/kubernetes/pod.rb
+++ b/lib/gitlab/kubernetes/pod.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Kubernetes
module Pod
diff --git a/lib/gitlab/legacy_github_import/base_formatter.rb b/lib/gitlab/legacy_github_import/base_formatter.rb
index 11d1300e51e..0b19cf742ed 100644
--- a/lib/gitlab/legacy_github_import/base_formatter.rb
+++ b/lib/gitlab/legacy_github_import/base_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class BaseFormatter
diff --git a/lib/gitlab/legacy_github_import/branch_formatter.rb b/lib/gitlab/legacy_github_import/branch_formatter.rb
index 80fe1d67209..1177751457f 100644
--- a/lib/gitlab/legacy_github_import/branch_formatter.rb
+++ b/lib/gitlab/legacy_github_import/branch_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class BranchFormatter < BaseFormatter
diff --git a/lib/gitlab/legacy_github_import/client.rb b/lib/gitlab/legacy_github_import/client.rb
index d8ed0ebca9d..bc952147667 100644
--- a/lib/gitlab/legacy_github_import/client.rb
+++ b/lib/gitlab/legacy_github_import/client.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class Client
diff --git a/lib/gitlab/legacy_github_import/comment_formatter.rb b/lib/gitlab/legacy_github_import/comment_formatter.rb
index d2c7a8ae9f4..d83cc4f6b3c 100644
--- a/lib/gitlab/legacy_github_import/comment_formatter.rb
+++ b/lib/gitlab/legacy_github_import/comment_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class CommentFormatter < BaseFormatter
diff --git a/lib/gitlab/legacy_github_import/importer.rb b/lib/gitlab/legacy_github_import/importer.rb
index c5bde681365..43695451b87 100644
--- a/lib/gitlab/legacy_github_import/importer.rb
+++ b/lib/gitlab/legacy_github_import/importer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class Importer
diff --git a/lib/gitlab/legacy_github_import/issuable_formatter.rb b/lib/gitlab/legacy_github_import/issuable_formatter.rb
index 7db4a54267e..1a0aefbbd62 100644
--- a/lib/gitlab/legacy_github_import/issuable_formatter.rb
+++ b/lib/gitlab/legacy_github_import/issuable_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class IssuableFormatter < BaseFormatter
diff --git a/lib/gitlab/legacy_github_import/issue_formatter.rb b/lib/gitlab/legacy_github_import/issue_formatter.rb
index 4c8825ccf19..2f46e2e30d1 100644
--- a/lib/gitlab/legacy_github_import/issue_formatter.rb
+++ b/lib/gitlab/legacy_github_import/issue_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class IssueFormatter < IssuableFormatter
diff --git a/lib/gitlab/legacy_github_import/label_formatter.rb b/lib/gitlab/legacy_github_import/label_formatter.rb
index e9663650903..89200e794d8 100644
--- a/lib/gitlab/legacy_github_import/label_formatter.rb
+++ b/lib/gitlab/legacy_github_import/label_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class LabelFormatter < BaseFormatter
diff --git a/lib/gitlab/legacy_github_import/milestone_formatter.rb b/lib/gitlab/legacy_github_import/milestone_formatter.rb
index a565294384d..2fe1b4258d3 100644
--- a/lib/gitlab/legacy_github_import/milestone_formatter.rb
+++ b/lib/gitlab/legacy_github_import/milestone_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class MilestoneFormatter < BaseFormatter
diff --git a/lib/gitlab/legacy_github_import/project_creator.rb b/lib/gitlab/legacy_github_import/project_creator.rb
index 5e96eb16754..ca1a1b8e9bd 100644
--- a/lib/gitlab/legacy_github_import/project_creator.rb
+++ b/lib/gitlab/legacy_github_import/project_creator.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class ProjectCreator
diff --git a/lib/gitlab/legacy_github_import/pull_request_formatter.rb b/lib/gitlab/legacy_github_import/pull_request_formatter.rb
index 94c2e99066a..5b847f13d4a 100644
--- a/lib/gitlab/legacy_github_import/pull_request_formatter.rb
+++ b/lib/gitlab/legacy_github_import/pull_request_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class PullRequestFormatter < IssuableFormatter
diff --git a/lib/gitlab/legacy_github_import/release_formatter.rb b/lib/gitlab/legacy_github_import/release_formatter.rb
index 3ed9d4f76da..8c0c17780ca 100644
--- a/lib/gitlab/legacy_github_import/release_formatter.rb
+++ b/lib/gitlab/legacy_github_import/release_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class ReleaseFormatter < BaseFormatter
diff --git a/lib/gitlab/legacy_github_import/user_formatter.rb b/lib/gitlab/legacy_github_import/user_formatter.rb
index 3794380e2d0..ec0e221b1ff 100644
--- a/lib/gitlab/legacy_github_import/user_formatter.rb
+++ b/lib/gitlab/legacy_github_import/user_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class UserFormatter
diff --git a/lib/gitlab/legacy_github_import/wiki_formatter.rb b/lib/gitlab/legacy_github_import/wiki_formatter.rb
index 27f45875c7c..ea52be5ee0f 100644
--- a/lib/gitlab/legacy_github_import/wiki_formatter.rb
+++ b/lib/gitlab/legacy_github_import/wiki_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module LegacyGithubImport
class WikiFormatter
diff --git a/lib/gitlab/manifest_import/manifest.rb b/lib/gitlab/manifest_import/manifest.rb
index b69b9ac4b64..7208fe5bbc5 100644
--- a/lib/gitlab/manifest_import/manifest.rb
+++ b/lib/gitlab/manifest_import/manifest.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Class to parse manifest file and build a list of repositories for import
#
# <manifest>
diff --git a/lib/gitlab/manifest_import/project_creator.rb b/lib/gitlab/manifest_import/project_creator.rb
index b5967c93735..837d65e5f7c 100644
--- a/lib/gitlab/manifest_import/project_creator.rb
+++ b/lib/gitlab/manifest_import/project_creator.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module ManifestImport
class ProjectCreator
diff --git a/lib/gitlab/metrics/background_transaction.rb b/lib/gitlab/metrics/background_transaction.rb
index 5919ebb1493..fe1722b1095 100644
--- a/lib/gitlab/metrics/background_transaction.rb
+++ b/lib/gitlab/metrics/background_transaction.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
class BackgroundTransaction < Transaction
diff --git a/lib/gitlab/metrics/delta.rb b/lib/gitlab/metrics/delta.rb
index bcf28eed84d..ab2d9e46390 100644
--- a/lib/gitlab/metrics/delta.rb
+++ b/lib/gitlab/metrics/delta.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
# Class for calculating the difference between two numeric values.
diff --git a/lib/gitlab/metrics/influx_db.rb b/lib/gitlab/metrics/influx_db.rb
index ce9d3ec3de4..1359e973590 100644
--- a/lib/gitlab/metrics/influx_db.rb
+++ b/lib/gitlab/metrics/influx_db.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
module InfluxDb
diff --git a/lib/gitlab/metrics/instrumentation.rb b/lib/gitlab/metrics/instrumentation.rb
index 023e9963493..651e241362c 100644
--- a/lib/gitlab/metrics/instrumentation.rb
+++ b/lib/gitlab/metrics/instrumentation.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
# Module for instrumenting methods.
diff --git a/lib/gitlab/metrics/method_call.rb b/lib/gitlab/metrics/method_call.rb
index f3290e3149c..85438011cb9 100644
--- a/lib/gitlab/metrics/method_call.rb
+++ b/lib/gitlab/metrics/method_call.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
# Class for tracking timing information about method calls
diff --git a/lib/gitlab/metrics/methods.rb b/lib/gitlab/metrics/methods.rb
index f79eb0cd1bf..447d03bfca4 100644
--- a/lib/gitlab/metrics/methods.rb
+++ b/lib/gitlab/metrics/methods.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# rubocop:disable Style/ClassVars
module Gitlab
diff --git a/lib/gitlab/metrics/methods/metric_options.rb b/lib/gitlab/metrics/methods/metric_options.rb
index 70e122d4e15..8e6ceb74c09 100644
--- a/lib/gitlab/metrics/methods/metric_options.rb
+++ b/lib/gitlab/metrics/methods/metric_options.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
module Methods
diff --git a/lib/gitlab/metrics/metric.rb b/lib/gitlab/metrics/metric.rb
index bd0afe53c51..9e4d70a71ff 100644
--- a/lib/gitlab/metrics/metric.rb
+++ b/lib/gitlab/metrics/metric.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
# Class for storing details of a single metric (label, value, etc).
diff --git a/lib/gitlab/metrics/null_metric.rb b/lib/gitlab/metrics/null_metric.rb
index aabada5c21a..7dbd2a1f8e3 100644
--- a/lib/gitlab/metrics/null_metric.rb
+++ b/lib/gitlab/metrics/null_metric.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
# Mocks ::Prometheus::Client::Metric and all derived metrics
diff --git a/lib/gitlab/metrics/prometheus.rb b/lib/gitlab/metrics/prometheus.rb
index d41a855bff1..cab1edab48f 100644
--- a/lib/gitlab/metrics/prometheus.rb
+++ b/lib/gitlab/metrics/prometheus.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'prometheus/client'
module Gitlab
diff --git a/lib/gitlab/metrics/rack_middleware.rb b/lib/gitlab/metrics/rack_middleware.rb
index 2d45765df3f..9aa97515961 100644
--- a/lib/gitlab/metrics/rack_middleware.rb
+++ b/lib/gitlab/metrics/rack_middleware.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
# Rack middleware for tracking Rails and Grape requests.
diff --git a/lib/gitlab/metrics/requests_rack_middleware.rb b/lib/gitlab/metrics/requests_rack_middleware.rb
index 0dc19f31d03..74c956ab5af 100644
--- a/lib/gitlab/metrics/requests_rack_middleware.rb
+++ b/lib/gitlab/metrics/requests_rack_middleware.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
class RequestsRackMiddleware
diff --git a/lib/gitlab/metrics/samplers/base_sampler.rb b/lib/gitlab/metrics/samplers/base_sampler.rb
index 37f90c4673d..6a062e93f0f 100644
--- a/lib/gitlab/metrics/samplers/base_sampler.rb
+++ b/lib/gitlab/metrics/samplers/base_sampler.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'logger'
module Gitlab
diff --git a/lib/gitlab/metrics/samplers/influx_sampler.rb b/lib/gitlab/metrics/samplers/influx_sampler.rb
index ad97632e4eb..c4c38b23a55 100644
--- a/lib/gitlab/metrics/samplers/influx_sampler.rb
+++ b/lib/gitlab/metrics/samplers/influx_sampler.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
module Samplers
diff --git a/lib/gitlab/metrics/samplers/ruby_sampler.rb b/lib/gitlab/metrics/samplers/ruby_sampler.rb
index 7b2b3bedf04..232a58a7d69 100644
--- a/lib/gitlab/metrics/samplers/ruby_sampler.rb
+++ b/lib/gitlab/metrics/samplers/ruby_sampler.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'prometheus/client/support/unicorn'
module Gitlab
diff --git a/lib/gitlab/metrics/samplers/unicorn_sampler.rb b/lib/gitlab/metrics/samplers/unicorn_sampler.rb
index ea325651fbb..4c4ec026823 100644
--- a/lib/gitlab/metrics/samplers/unicorn_sampler.rb
+++ b/lib/gitlab/metrics/samplers/unicorn_sampler.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
module Samplers
diff --git a/lib/gitlab/metrics/sidekiq_metrics_exporter.rb b/lib/gitlab/metrics/sidekiq_metrics_exporter.rb
index 47b4af5d649..56e106b9612 100644
--- a/lib/gitlab/metrics/sidekiq_metrics_exporter.rb
+++ b/lib/gitlab/metrics/sidekiq_metrics_exporter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'webrick'
require 'prometheus/client/rack/exporter'
diff --git a/lib/gitlab/metrics/sidekiq_middleware.rb b/lib/gitlab/metrics/sidekiq_middleware.rb
index df4bdf16847..0b4485feea9 100644
--- a/lib/gitlab/metrics/sidekiq_middleware.rb
+++ b/lib/gitlab/metrics/sidekiq_middleware.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
# Sidekiq middleware for tracking jobs.
diff --git a/lib/gitlab/metrics/subscribers/action_view.rb b/lib/gitlab/metrics/subscribers/action_view.rb
index b600e8a2a50..c068f8017fd 100644
--- a/lib/gitlab/metrics/subscribers/action_view.rb
+++ b/lib/gitlab/metrics/subscribers/action_view.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
module Subscribers
diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb
index 04107296ae3..a02dd850582 100644
--- a/lib/gitlab/metrics/subscribers/active_record.rb
+++ b/lib/gitlab/metrics/subscribers/active_record.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
module Subscribers
diff --git a/lib/gitlab/metrics/subscribers/rails_cache.rb b/lib/gitlab/metrics/subscribers/rails_cache.rb
index 250897a79c2..f633e1a9d7c 100644
--- a/lib/gitlab/metrics/subscribers/rails_cache.rb
+++ b/lib/gitlab/metrics/subscribers/rails_cache.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
module Subscribers
diff --git a/lib/gitlab/metrics/system.rb b/lib/gitlab/metrics/system.rb
index e60e245cf89..426496855e3 100644
--- a/lib/gitlab/metrics/system.rb
+++ b/lib/gitlab/metrics/system.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
# Module for gathering system/process statistics such as the memory usage.
diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb
index 9f903e96585..468d7cb56fc 100644
--- a/lib/gitlab/metrics/transaction.rb
+++ b/lib/gitlab/metrics/transaction.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
# Class for storing metrics information of a single transaction.
diff --git a/lib/gitlab/metrics/web_transaction.rb b/lib/gitlab/metrics/web_transaction.rb
index 723ca576aab..b2a43d46fb2 100644
--- a/lib/gitlab/metrics/web_transaction.rb
+++ b/lib/gitlab/metrics/web_transaction.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Metrics
class WebTransaction < Transaction
@@ -40,7 +42,7 @@ module Gitlab
# increasing the cardinality of our metrics, we limit the number of
# possible suffixes.
if suffix && ALLOWED_SUFFIXES.include?(suffix)
- action += ".#{suffix}"
+ action = "#{action}.#{suffix}"
end
{ controller: controller.class.name, action: action }
diff --git a/lib/gitlab/middleware/go.rb b/lib/gitlab/middleware/go.rb
index 6943567fb6d..d1a87c3b3bb 100644
--- a/lib/gitlab/middleware/go.rb
+++ b/lib/gitlab/middleware/go.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# A dumb middleware that returns a Go HTML document if the go-get=1 query string
# is used irrespective if the namespace/project exists
module Gitlab
diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb
index 10cb1e7127e..84c2f0d5720 100644
--- a/lib/gitlab/middleware/multipart.rb
+++ b/lib/gitlab/middleware/multipart.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Gitlab::Middleware::Multipart - a Rack::Multipart replacement
#
# Rack::Multipart leaves behind tempfiles in /tmp and uses valuable Ruby
diff --git a/lib/gitlab/middleware/rails_queue_duration.rb b/lib/gitlab/middleware/rails_queue_duration.rb
index bc70b2459ef..96c6a0a7d28 100644
--- a/lib/gitlab/middleware/rails_queue_duration.rb
+++ b/lib/gitlab/middleware/rails_queue_duration.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This Rack middleware is intended to measure the latency between
# gitlab-workhorse forwarding a request to the Rails application and the
# time this middleware is reached.
diff --git a/lib/gitlab/middleware/read_only.rb b/lib/gitlab/middleware/read_only.rb
index 7f63e39b3aa..83c52a6c6e0 100644
--- a/lib/gitlab/middleware/read_only.rb
+++ b/lib/gitlab/middleware/read_only.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Middleware
class ReadOnly
diff --git a/lib/gitlab/middleware/read_only/controller.rb b/lib/gitlab/middleware/read_only/controller.rb
index 8dca431c005..89941a9efa0 100644
--- a/lib/gitlab/middleware/read_only/controller.rb
+++ b/lib/gitlab/middleware/read_only/controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Middleware
class ReadOnly
diff --git a/lib/gitlab/middleware/release_env.rb b/lib/gitlab/middleware/release_env.rb
index bfe8e113b5e..849cf8f759b 100644
--- a/lib/gitlab/middleware/release_env.rb
+++ b/lib/gitlab/middleware/release_env.rb
@@ -1,4 +1,7 @@
-module Gitlab # rubocop:disable Naming/FileName
+# rubocop:disable Naming/FileName
+# frozen_string_literal: true
+
+module Gitlab
module Middleware
# Some of middleware would hold env for no good reason even after the
# request had already been processed, and we could not garbage collect
diff --git a/lib/gitlab/middleware/static.rb b/lib/gitlab/middleware/static.rb
index aa1e9dc0fdb..972fed2134c 100644
--- a/lib/gitlab/middleware/static.rb
+++ b/lib/gitlab/middleware/static.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Middleware
class Static < ActionDispatch::Static
diff --git a/lib/gitlab/repository_cache.rb b/lib/gitlab/repository_cache.rb
index 56007574b1b..6b0808f5304 100644
--- a/lib/gitlab/repository_cache.rb
+++ b/lib/gitlab/repository_cache.rb
@@ -7,13 +7,13 @@ module Gitlab
def initialize(repository, extra_namespace: nil, backend: Rails.cache)
@repository = repository
- @namespace = "#{repository.full_path}:#{repository.project.id}"
+ @namespace = "project:#{repository.project.id}"
@namespace = "#{@namespace}:#{extra_namespace}" if extra_namespace
@backend = backend
end
def cache_key(type)
- "#{type}:#{namespace}"
+ "#{namespace}:#{type}"
end
def expire(key)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index f18821adb5f..c021d1aad1c 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2211,6 +2211,9 @@ msgstr ""
msgid "Define a custom pattern with cron syntax"
msgstr ""
+msgid "Define environments in the deploy stage(s) in <code>.gitlab-ci.yml</code> to track deployments here."
+msgstr ""
+
msgid "DelayedJobs|Are you sure you want to run %{jobName} immediately? Otherwise this job will run automatically after it's timer finishes."
msgstr ""
@@ -2510,6 +2513,9 @@ msgstr ""
msgid "Edit application"
msgstr ""
+msgid "Edit environment"
+msgstr ""
+
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -2588,6 +2594,9 @@ msgstr ""
msgid "Environments"
msgstr ""
+msgid "Environments allow you to track deployments of your application %{link_to_read_more}."
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -2657,6 +2666,9 @@ msgstr ""
msgid "Environments|Stop environment"
msgstr ""
+msgid "Environments|Stopping"
+msgstr ""
+
msgid "Environments|Updated"
msgstr ""
@@ -2792,6 +2804,9 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "External URL"
+msgstr ""
+
msgid "Facebook"
msgstr ""
@@ -3881,6 +3896,9 @@ msgstr ""
msgid "Metrics and profiling"
msgstr ""
+msgid "Metrics for environment"
+msgstr ""
+
msgid "Metrics|Check out the CI/CD documentation on deploying to an environment"
msgstr ""
@@ -4025,6 +4043,9 @@ msgstr ""
msgid "New Application"
msgstr ""
+msgid "New Environment"
+msgstr ""
+
msgid "New Group"
msgstr ""
@@ -4057,6 +4078,9 @@ msgstr ""
msgid "New directory"
msgstr ""
+msgid "New environment"
+msgstr ""
+
msgid "New file"
msgstr ""
@@ -4434,6 +4458,9 @@ msgstr ""
msgid "Personal Access Token"
msgstr ""
+msgid "Pick a name"
+msgstr ""
+
msgid "Pipeline"
msgstr ""
@@ -5130,6 +5157,9 @@ msgstr ""
msgid "Read more"
msgstr ""
+msgid "Read more about environments"
+msgstr ""
+
msgid "Read more about project permissions <strong>%{link_to_help}</strong>"
msgstr ""
@@ -5156,6 +5186,9 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
+msgid "Register U2F device"
+msgstr ""
+
msgid "Register and see your runners for this group."
msgstr ""
@@ -5503,6 +5536,9 @@ msgstr ""
msgid "Secret"
msgstr ""
+msgid "See metrics"
+msgstr ""
+
msgid "Select"
msgstr ""
@@ -5596,6 +5632,9 @@ msgstr ""
msgid "Set up a specific Runner automatically"
msgstr ""
+msgid "Set up new U2F device"
+msgstr ""
+
msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically."
msgstr ""
@@ -5676,6 +5715,9 @@ msgstr ""
msgid "Sign in / Register"
msgstr ""
+msgid "Sign in via 2FA code"
+msgstr ""
+
msgid "Sign out"
msgstr ""
@@ -5961,9 +6003,6 @@ msgstr ""
msgid "Subscribed"
msgstr ""
-msgid "Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})"
-msgstr ""
-
msgid "Switch branch/tag"
msgstr ""
@@ -6077,6 +6116,9 @@ msgstr ""
msgid "Templates"
msgstr ""
+msgid "Terminal for environment"
+msgstr ""
+
msgid "Terms of Service Agreement and Privacy Policy"
msgstr ""
@@ -6681,6 +6723,12 @@ msgstr ""
msgid "Try again"
msgstr ""
+msgid "Try again?"
+msgstr ""
+
+msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
+msgstr ""
+
msgid "Twitter"
msgstr ""
@@ -6837,9 +6885,6 @@ msgstr ""
msgid "UserProfile|Personal projects"
msgstr ""
-msgid "UserProfile|Recent contributions"
-msgstr ""
-
msgid "UserProfile|Report abuse"
msgstr ""
@@ -6885,6 +6930,9 @@ msgstr ""
msgid "View app"
msgstr ""
+msgid "View deployment"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -6948,6 +6996,9 @@ msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
+msgid "We heard back from your U2F device. You have been authenticated."
+msgstr ""
+
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
@@ -7182,6 +7233,9 @@ msgstr ""
msgid "You don't have any authorized applications"
msgstr ""
+msgid "You don't have any deployments right now."
+msgstr ""
+
msgid "You have no permissions"
msgstr ""
@@ -7197,6 +7251,9 @@ msgstr ""
msgid "You need permission."
msgstr ""
+msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgstr ""
+
msgid "You will loose all changes you've made to this file. This action cannot be undone."
msgstr ""
@@ -7257,12 +7314,18 @@ msgstr ""
msgid "Your Todos"
msgstr ""
+msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
msgid "Your authorized applications"
msgstr ""
+msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -7272,6 +7335,9 @@ msgstr ""
msgid "Your comment will not be visible to the public."
msgstr ""
+msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
+msgstr ""
+
msgid "Your groups"
msgstr ""
@@ -7325,6 +7391,9 @@ msgstr ""
msgid "enabled"
msgstr ""
+msgid "error code:"
+msgstr ""
+
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb
index 16f0b311fa9..9be88ba4211 100644
--- a/qa/qa/resource/user.rb
+++ b/qa/qa/resource/user.rb
@@ -76,6 +76,17 @@ module QA
}
end
+ def self.fabricate_or_use(username, password)
+ if Runtime::Env.signup_disabled?
+ self.new.tap do |user|
+ user.username = username
+ user.password = password
+ end
+ else
+ self.fabricate!
+ end
+ end
+
private
def fetch_id(username)
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index c4500f9be90..1154eaca6a9 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -75,6 +75,22 @@ module QA
ENV['GITLAB_FORKER_PASSWORD']
end
+ def gitlab_qa_username_1
+ ENV['GITLAB_QA_USERNAME_1'] || 'gitlab-qa-user1'
+ end
+
+ def gitlab_qa_password_1
+ ENV['GITLAB_QA_PASSWORD_1']
+ end
+
+ def gitlab_qa_username_2
+ ENV['GITLAB_QA_USERNAME_2'] || 'gitlab-qa-user2'
+ end
+
+ def gitlab_qa_password_2
+ ENV['GITLAB_QA_PASSWORD_2']
+ end
+
def ldap_username
ENV['GITLAB_LDAP_USERNAME']
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
index bef89d5be24..4070a225260 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
@@ -7,7 +7,7 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
- user = Resource::User.fabricate!
+ user = Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1)
project = Resource::Project.fabricate! do |resource|
resource.name = 'add-member-project'
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index a1f93bd3fbd..8cb9b57a049 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -64,7 +64,7 @@ describe 'Contributions Calendar', :js do
end
def selected_day_activities(visible: true)
- find('.tab-pane#activity .user-calendar-activities', visible: visible).text
+ find('#js-overview .user-calendar-activities', visible: visible).text
end
before do
@@ -74,16 +74,16 @@ describe 'Contributions Calendar', :js do
describe 'calendar day selection' do
before do
visit user.username
- page.find('.js-activity-tab a').click
+ page.find('.js-overview-tab a').click
wait_for_requests
end
it 'displays calendar' do
- expect(find('.tab-pane#activity')).to have_css('.js-contrib-calendar')
+ expect(find('#js-overview')).to have_css('.js-contrib-calendar')
end
describe 'select calendar day' do
- let(:cells) { page.all('.tab-pane#activity .user-contrib-cell') }
+ let(:cells) { page.all('#js-overview .user-contrib-cell') }
before do
cells[0].click
@@ -109,7 +109,7 @@ describe 'Contributions Calendar', :js do
describe 'deselect calendar day' do
before do
cells[0].click
- page.find('.js-activity-tab a').click
+ page.find('.js-overview-tab a').click
wait_for_requests
end
@@ -124,7 +124,7 @@ describe 'Contributions Calendar', :js do
shared_context 'visit user page' do
before do
visit user.username
- page.find('.js-activity-tab a').click
+ page.find('.js-overview-tab a').click
wait_for_requests
end
end
@@ -133,12 +133,12 @@ describe 'Contributions Calendar', :js do
include_context 'visit user page'
it 'displays calendar activity square color for 1 contribution' do
- expect(find('.tab-pane#activity')).to have_selector(get_cell_color_selector(contribution_count), count: 1)
+ expect(find('#js-overview')).to have_selector(get_cell_color_selector(contribution_count), count: 1)
end
it 'displays calendar activity square on the correct date' do
today = Date.today.strftime(date_format)
- expect(find('.tab-pane#activity')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
+ expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
end
end
@@ -153,7 +153,7 @@ describe 'Contributions Calendar', :js do
include_context 'visit user page'
it 'displays calendar activity log' do
- expect(find('.tab-pane#activity .content_list .event-target-title')).to have_content issue_title
+ expect(find('#js-overview .overview-content-list .event-target-title')).to have_content issue_title
end
end
end
@@ -185,17 +185,17 @@ describe 'Contributions Calendar', :js do
include_context 'visit user page'
it 'displays calendar activity squares for both days' do
- expect(find('.tab-pane#activity')).to have_selector(get_cell_color_selector(1), count: 2)
+ expect(find('#js-overview')).to have_selector(get_cell_color_selector(1), count: 2)
end
it 'displays calendar activity square for yesterday' do
yesterday = Date.yesterday.strftime(date_format)
- expect(find('.tab-pane#activity')).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
+ expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
end
it 'displays calendar activity square for today' do
today = Date.today.strftime(date_format)
- expect(find('.tab-pane#activity')).to have_selector(get_cell_date_selector(1, today), count: 1)
+ expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, today), count: 1)
end
end
end
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index 605860b90cd..7c591dacce5 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -1,6 +1,10 @@
require 'rails_helper'
describe 'GFM autocomplete', :js do
+ let(:issue_xss_title) { 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
+ let(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
+
+ let(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let(:project) { create(:project) }
let(:label) { create(:label, project: project, title: 'special+') }
@@ -9,6 +13,8 @@ describe 'GFM autocomplete', :js do
before do
project.add_maintainer(user)
+ project.add_maintainer(user_xss)
+
sign_in(user)
visit project_issue_path(project, issue)
@@ -35,9 +41,8 @@ describe 'GFM autocomplete', :js do
expect(page).to have_selector('.atwho-container')
end
- it 'opens autocomplete menu when field starts with text with item escaping HTML characters' do
- alert_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;'
- create(:issue, project: project, title: alert_title)
+ it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
+ create(:issue, project: project, title: issue_xss_title)
page.within '.timeline-content-form' do
find('#note-body').native.send_keys('#')
@@ -46,7 +51,19 @@ describe 'GFM autocomplete', :js do
expect(page).to have_selector('.atwho-container')
page.within '.atwho-container #at-view-issues' do
- expect(page.all('li').first.text).to include(alert_title)
+ expect(page.all('li').first.text).to include(issue_xss_title)
+ end
+ end
+
+ it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('@ev')
+ end
+
+ expect(page).to have_selector('.atwho-container')
+
+ page.within '.atwho-container #at-view-users' do
+ expect(find('li').text).to have_content(user_xss.username)
end
end
@@ -107,7 +124,7 @@ describe 'GFM autocomplete', :js do
wait_for_requests
- expect(find('#at-view-64')).to have_selector('.cur:first-of-type')
+ expect(find('#at-view-users')).to have_selector('.cur:first-of-type')
end
it 'includes items for assignee dropdowns with non-ASCII characters in name' do
@@ -120,7 +137,7 @@ describe 'GFM autocomplete', :js do
wait_for_requests
- expect(find('#at-view-64')).to have_content(user.name)
+ expect(find('#at-view-users')).to have_content(user.name)
end
it 'selects the first item for non-assignee dropdowns if a query is entered' do
diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
index 297cd808460..32bc851f00f 100644
--- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
+++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
@@ -76,7 +76,7 @@ describe 'User creates branch and merge request on issue page', :js do
visit project_issue_path(project, issue)
- expect(page).to have_content('created branch 1-cherry-coloured-funk')
+ expect(page).to have_content("created merge request !1 to address this issue")
expect(page).to have_content('mentioned in merge request !1')
end
@@ -106,7 +106,7 @@ describe 'User creates branch and merge request on issue page', :js do
visit project_issue_path(project, issue)
- expect(page).to have_content('created branch custom-branch-name')
+ expect(page).to have_content("created merge request !1 to address this issue")
expect(page).to have_content('mentioned in merge request !1')
end
diff --git a/spec/features/issues/user_uses_quick_actions_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb
index 5926e442f24..27cffdc5f8b 100644
--- a/spec/features/issues/user_uses_quick_actions_spec.rb
+++ b/spec/features/issues/user_uses_quick_actions_spec.rb
@@ -303,5 +303,63 @@ describe 'Issues > User uses quick actions', :js do
end
end
end
+
+ describe 'create a merge request starting from an issue' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:issue) { create(:issue, project: project) }
+
+ def expect_mr_quickaction(success)
+ expect(page).to have_content 'Commands applied'
+
+ if success
+ expect(page).to have_content 'created merge request'
+ else
+ expect(page).not_to have_content 'created merge request'
+ end
+ end
+
+ it "doesn't create a merge request when the branch name is invalid" do
+ add_note("/create_merge_request invalid branch name")
+
+ wait_for_requests
+
+ expect_mr_quickaction(false)
+ end
+
+ it "doesn't create a merge request when a branch with that name already exists" do
+ add_note("/create_merge_request feature")
+
+ wait_for_requests
+
+ expect_mr_quickaction(false)
+ end
+
+ it 'creates a new merge request using issue iid and title as branch name when the branch name is empty' do
+ add_note("/create_merge_request")
+
+ wait_for_requests
+
+ expect_mr_quickaction(true)
+
+ created_mr = project.merge_requests.last
+ expect(created_mr.source_branch).to eq(issue.to_branch_name)
+
+ visit project_merge_request_path(project, created_mr)
+ expect(page).to have_content %{WIP: Resolve "#{issue.title}"}
+ end
+
+ it 'creates a merge request using the given branch name' do
+ branch_name = '1-feature'
+ add_note("/create_merge_request #{branch_name}")
+
+ expect_mr_quickaction(true)
+
+ created_mr = project.merge_requests.last
+ expect(created_mr.source_branch).to eq(branch_name)
+
+ visit project_merge_request_path(project, created_mr)
+ expect(page).to have_content %{WIP: Resolve "#{issue.title}"}
+ end
+ end
end
end
diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
index 2ce5ee0e87d..7ad7fec922a 100644
--- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
@@ -1,233 +1,223 @@
require 'spec_helper'
describe 'User updates wiki page' do
- shared_examples 'wiki page user update' do
- let(:user) { create(:user) }
+ let(:user) { create(:user) }
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ context 'when wiki is empty' do
before do
- project.add_maintainer(user)
- sign_in(user)
+ visit(project_wikis_path(project))
+ click_link "Create your first page"
end
- context 'when wiki is empty' do
- before do
- visit(project_wikis_path(project))
- click_link "Create your first page"
- end
-
- context 'in a user namespace' do
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
+ context 'in a user namespace' do
+ let(:project) { create(:project, :wiki_repo) }
- it 'redirects back to the home edit page' do
- page.within(:css, '.wiki-form .form-actions') do
- click_on('Cancel')
- end
-
- expect(current_path).to eq project_wiki_path(project, :home)
+ it 'redirects back to the home edit page' do
+ page.within(:css, '.wiki-form .form-actions') do
+ click_on('Cancel')
end
- it 'updates a page that has a path', :js do
- click_on('New page')
+ expect(current_path).to eq project_wiki_path(project, :home)
+ end
- page.within('#modal-new-wiki') do
- fill_in(:new_wiki_path, with: 'one/two/three-test')
- click_on('Create page')
- end
+ it 'updates a page that has a path', :js do
+ click_on('New page')
- page.within '.wiki-form' do
- fill_in(:wiki_content, with: 'wiki content')
- click_on('Create page')
- end
+ page.within('#modal-new-wiki') do
+ fill_in(:new_wiki_path, with: 'one/two/three-test')
+ click_on('Create page')
+ end
- expect(current_path).to include('one/two/three-test')
- expect(find('.wiki-pages')).to have_content('Three')
+ page.within '.wiki-form' do
+ fill_in(:wiki_content, with: 'wiki content')
+ click_on('Create page')
+ end
- first(:link, text: 'Three').click
+ expect(current_path).to include('one/two/three-test')
+ expect(find('.wiki-pages')).to have_content('Three')
- expect(find('.nav-text')).to have_content('Three')
+ first(:link, text: 'Three').click
- click_on('Edit')
+ expect(find('.nav-text')).to have_content('Three')
- expect(current_path).to include('one/two/three-test')
- expect(page).to have_content('Edit Page')
+ click_on('Edit')
- fill_in('Content', with: 'Updated Wiki Content')
- click_on('Save changes')
+ expect(current_path).to include('one/two/three-test')
+ expect(page).to have_content('Edit Page')
- expect(page).to have_content('Updated Wiki Content')
- end
+ fill_in('Content', with: 'Updated Wiki Content')
+ click_on('Save changes')
- it_behaves_like 'wiki file attachments'
+ expect(page).to have_content('Updated Wiki Content')
end
- end
- context 'when wiki is not empty' do
- let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
- let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: 'home', content: 'Home page' }) }
+ it_behaves_like 'wiki file attachments'
+ end
+ end
- before do
- visit(project_wikis_path(project))
+ context 'when wiki is not empty' do
+ let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
+ let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: 'home', content: 'Home page' }) }
- click_link('Edit')
- end
+ before do
+ visit(project_wikis_path(project))
- context 'in a user namespace' do
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
+ click_link('Edit')
+ end
- it 'updates a page' do
- # Commit message field should have correct value.
- expect(page).to have_field('wiki[message]', with: 'Update home')
+ context 'in a user namespace' do
+ let(:project) { create(:project, :wiki_repo) }
- fill_in(:wiki_content, with: 'My awesome wiki!')
- click_button('Save changes')
+ it 'updates a page' do
+ # Commit message field should have correct value.
+ expect(page).to have_field('wiki[message]', with: 'Update home')
- expect(page).to have_content('Home')
- expect(page).to have_content("Last edited by #{user.name}")
- expect(page).to have_content('My awesome wiki!')
- end
+ fill_in(:wiki_content, with: 'My awesome wiki!')
+ click_button('Save changes')
- it 'shows a validation error message' do
- fill_in(:wiki_content, with: '')
- click_button('Save changes')
+ expect(page).to have_content('Home')
+ expect(page).to have_content("Last edited by #{user.name}")
+ expect(page).to have_content('My awesome wiki!')
+ end
- expect(page).to have_selector('.wiki-form')
- expect(page).to have_content('Edit Page')
- expect(page).to have_content('The form contains the following error:')
- expect(page).to have_content("Content can't be blank")
- expect(find('textarea#wiki_content').value).to eq('')
- end
+ it 'shows a validation error message' do
+ fill_in(:wiki_content, with: '')
+ click_button('Save changes')
- it 'shows the emoji autocompletion dropdown', :js do
- find('#wiki_content').native.send_keys('')
- fill_in(:wiki_content, with: ':')
+ expect(page).to have_selector('.wiki-form')
+ expect(page).to have_content('Edit Page')
+ expect(page).to have_content('The form contains the following error:')
+ expect(page).to have_content("Content can't be blank")
+ expect(find('textarea#wiki_content').value).to eq('')
+ end
- expect(page).to have_selector('.atwho-view')
- end
+ it 'shows the emoji autocompletion dropdown', :js do
+ find('#wiki_content').native.send_keys('')
+ fill_in(:wiki_content, with: ':')
- it 'shows the error message' do
- wiki_page.update(content: 'Update')
+ expect(page).to have_selector('.atwho-view')
+ end
- click_button('Save changes')
+ it 'shows the error message' do
+ wiki_page.update(content: 'Update')
- expect(page).to have_content('Someone edited the page the same time you did.')
- end
+ click_button('Save changes')
- it 'updates a page' do
- fill_in('Content', with: 'Updated Wiki Content')
- click_on('Save changes')
+ expect(page).to have_content('Someone edited the page the same time you did.')
+ end
- expect(page).to have_content('Updated Wiki Content')
- end
+ it 'updates a page' do
+ fill_in('Content', with: 'Updated Wiki Content')
+ click_on('Save changes')
- it 'cancels editing of a page' do
- page.within(:css, '.wiki-form .form-actions') do
- click_on('Cancel')
- end
+ expect(page).to have_content('Updated Wiki Content')
+ end
- expect(current_path).to eq(project_wiki_path(project, wiki_page))
+ it 'cancels editing of a page' do
+ page.within(:css, '.wiki-form .form-actions') do
+ click_on('Cancel')
end
- it_behaves_like 'wiki file attachments'
+ expect(current_path).to eq(project_wiki_path(project, wiki_page))
end
- context 'in a group namespace' do
- let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) }
+ it_behaves_like 'wiki file attachments'
+ end
- it 'updates a page' do
- # Commit message field should have correct value.
- expect(page).to have_field('wiki[message]', with: 'Update home')
+ context 'in a group namespace' do
+ let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) }
- fill_in(:wiki_content, with: 'My awesome wiki!')
+ it 'updates a page' do
+ # Commit message field should have correct value.
+ expect(page).to have_field('wiki[message]', with: 'Update home')
- click_button('Save changes')
+ fill_in(:wiki_content, with: 'My awesome wiki!')
- expect(page).to have_content('Home')
- expect(page).to have_content("Last edited by #{user.name}")
- expect(page).to have_content('My awesome wiki!')
- end
+ click_button('Save changes')
- it_behaves_like 'wiki file attachments'
+ expect(page).to have_content('Home')
+ expect(page).to have_content("Last edited by #{user.name}")
+ expect(page).to have_content('My awesome wiki!')
end
- end
- context 'when the page is in a subdir' do
- let!(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
- let(:page_name) { 'page_name' }
- let(:page_dir) { "foo/bar/#{page_name}" }
- let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: page_dir, content: 'Home page' }) }
+ it_behaves_like 'wiki file attachments'
+ end
+ end
- before do
- visit(project_wiki_edit_path(project, wiki_page))
- end
+ context 'when the page is in a subdir' do
+ let!(:project) { create(:project, :wiki_repo) }
+ let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
+ let(:page_name) { 'page_name' }
+ let(:page_dir) { "foo/bar/#{page_name}" }
+ let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: page_dir, content: 'Home page' }) }
- it 'moves the page to the root folder', :skip_gitaly_mock do
- fill_in(:wiki_title, with: "/#{page_name}")
+ before do
+ visit(project_wiki_edit_path(project, wiki_page))
+ end
- click_button('Save changes')
+ it 'moves the page to the root folder' do
+ fill_in(:wiki_title, with: "/#{page_name}")
- expect(current_path).to eq(project_wiki_path(project, page_name))
- end
+ click_button('Save changes')
- it 'moves the page to other dir' do
- new_page_dir = "foo1/bar1/#{page_name}"
+ expect(current_path).to eq(project_wiki_path(project, page_name))
+ end
- fill_in(:wiki_title, with: new_page_dir)
+ it 'moves the page to other dir' do
+ new_page_dir = "foo1/bar1/#{page_name}"
- click_button('Save changes')
+ fill_in(:wiki_title, with: new_page_dir)
- expect(current_path).to eq(project_wiki_path(project, new_page_dir))
- end
+ click_button('Save changes')
- it 'remains in the same place if title has not changed' do
- original_path = project_wiki_path(project, wiki_page)
+ expect(current_path).to eq(project_wiki_path(project, new_page_dir))
+ end
- fill_in(:wiki_title, with: page_name)
+ it 'remains in the same place if title has not changed' do
+ original_path = project_wiki_path(project, wiki_page)
- click_button('Save changes')
+ fill_in(:wiki_title, with: page_name)
- expect(current_path).to eq(original_path)
- end
+ click_button('Save changes')
- it 'can be moved to a different dir with a different name' do
- new_page_dir = "foo1/bar1/new_page_name"
+ expect(current_path).to eq(original_path)
+ end
- fill_in(:wiki_title, with: new_page_dir)
+ it 'can be moved to a different dir with a different name' do
+ new_page_dir = "foo1/bar1/new_page_name"
- click_button('Save changes')
+ fill_in(:wiki_title, with: new_page_dir)
- expect(current_path).to eq(project_wiki_path(project, new_page_dir))
- end
+ click_button('Save changes')
- it 'can be renamed and moved to the root folder' do
- new_name = 'new_page_name'
+ expect(current_path).to eq(project_wiki_path(project, new_page_dir))
+ end
- fill_in(:wiki_title, with: "/#{new_name}")
+ it 'can be renamed and moved to the root folder' do
+ new_name = 'new_page_name'
- click_button('Save changes')
+ fill_in(:wiki_title, with: "/#{new_name}")
- expect(current_path).to eq(project_wiki_path(project, new_name))
- end
+ click_button('Save changes')
- it 'squishes the title before creating the page' do
- new_page_dir = " foo1 / bar1 / #{page_name} "
+ expect(current_path).to eq(project_wiki_path(project, new_name))
+ end
- fill_in(:wiki_title, with: new_page_dir)
+ it 'squishes the title before creating the page' do
+ new_page_dir = " foo1 / bar1 / #{page_name} "
- click_button('Save changes')
+ fill_in(:wiki_title, with: new_page_dir)
- expect(current_path).to eq(project_wiki_path(project, "foo1/bar1/#{page_name}"))
- end
+ click_button('Save changes')
- it_behaves_like 'wiki file attachments'
+ expect(current_path).to eq(project_wiki_path(project, "foo1/bar1/#{page_name}"))
end
- end
-
- context 'when Gitaly is enabled' do
- it_behaves_like 'wiki page user update'
- end
- context 'when Gitaly is disabled', :skip_gitaly_mock do
- it_behaves_like 'wiki page user update'
+ it_behaves_like 'wiki file attachments'
end
end
diff --git a/spec/features/projects/wiki/user_views_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_page_spec.rb
index 4b974a3ca10..3c93d71ab00 100644
--- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_views_wiki_page_spec.rb
@@ -1,174 +1,164 @@
require 'spec_helper'
describe 'User views a wiki page' do
- shared_examples 'wiki page user view' do
- include WikiHelpers
-
- let(:user) { create(:user) }
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- let(:path) { 'image.png' }
- let(:wiki_page) do
- create(:wiki_page,
- wiki: project.wiki,
- attrs: { title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})" })
- end
+ include WikiHelpers
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
+ let(:path) { 'image.png' }
+ let(:wiki_page) do
+ create(:wiki_page,
+ wiki: project.wiki,
+ attrs: { title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})" })
+ end
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
- context 'when wiki is empty' do
- before do
- visit(project_wikis_path(project))
- click_link "Create your first page"
+ context 'when wiki is empty' do
+ before do
+ visit(project_wikis_path(project))
+ click_link "Create your first page"
- click_on('New page')
+ click_on('New page')
- page.within('#modal-new-wiki') do
- fill_in(:new_wiki_path, with: 'one/two/three-test')
- click_on('Create page')
- end
+ page.within('#modal-new-wiki') do
+ fill_in(:new_wiki_path, with: 'one/two/three-test')
+ click_on('Create page')
+ end
- page.within('.wiki-form') do
- fill_in(:wiki_content, with: 'wiki content')
- click_on('Create page')
- end
+ page.within('.wiki-form') do
+ fill_in(:wiki_content, with: 'wiki content')
+ click_on('Create page')
end
+ end
- it 'shows the history of a page that has a path', :js do
- expect(current_path).to include('one/two/three-test')
+ it 'shows the history of a page that has a path', :js do
+ expect(current_path).to include('one/two/three-test')
- first(:link, text: 'Three').click
- click_on('Page history')
+ first(:link, text: 'Three').click
+ click_on('Page history')
- expect(current_path).to include('one/two/three-test')
+ expect(current_path).to include('one/two/three-test')
- page.within(:css, '.nav-text') do
- expect(page).to have_content('History')
- end
+ page.within(:css, '.nav-text') do
+ expect(page).to have_content('History')
end
+ end
- it 'shows an old version of a page', :js do
- expect(current_path).to include('one/two/three-test')
- expect(find('.wiki-pages')).to have_content('Three')
-
- first(:link, text: 'Three').click
-
- expect(find('.nav-text')).to have_content('Three')
+ it 'shows an old version of a page', :js do
+ expect(current_path).to include('one/two/three-test')
+ expect(find('.wiki-pages')).to have_content('Three')
- click_on('Edit')
+ first(:link, text: 'Three').click
- expect(current_path).to include('one/two/three-test')
- expect(page).to have_content('Edit Page')
+ expect(find('.nav-text')).to have_content('Three')
- fill_in('Content', with: 'Updated Wiki Content')
+ click_on('Edit')
- click_on('Save changes')
- click_on('Page history')
+ expect(current_path).to include('one/two/three-test')
+ expect(page).to have_content('Edit Page')
- page.within(:css, '.nav-text') do
- expect(page).to have_content('History')
- end
+ fill_in('Content', with: 'Updated Wiki Content')
- find('a[href*="?version_id"]')
- end
- end
-
- context 'when a page does not have history' do
- before do
- visit(project_wiki_path(project, wiki_page))
- end
+ click_on('Save changes')
+ click_on('Page history')
- it 'shows all the pages' do
- expect(page).to have_content(user.name)
- expect(find('.wiki-pages')).to have_content(wiki_page.title.capitalize)
+ page.within(:css, '.nav-text') do
+ expect(page).to have_content('History')
end
- context 'shows a file stored in a page' do
- let(:path) { upload_file_to_wiki(project, user, 'dk.png') }
+ find('a[href*="?version_id"]')
+ end
+ end
- it do
- expect(page).to have_xpath("//img[@data-src='#{project.wiki.wiki_base_path}/#{path}']")
- expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/#{path}")
+ context 'when a page does not have history' do
+ before do
+ visit(project_wiki_path(project, wiki_page))
+ end
- click_on('image')
+ it 'shows all the pages' do
+ expect(page).to have_content(user.name)
+ expect(find('.wiki-pages')).to have_content(wiki_page.title.capitalize)
+ end
- expect(current_path).to match("wikis/#{path}")
- expect(page).not_to have_xpath('/html') # Page should render the image which means there is no html involved
- end
- end
+ context 'shows a file stored in a page' do
+ let(:path) { upload_file_to_wiki(project, user, 'dk.png') }
- it 'shows the creation page if file does not exist' do
+ it do
+ expect(page).to have_xpath("//img[@data-src='#{project.wiki.wiki_base_path}/#{path}']")
expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/#{path}")
click_on('image')
expect(current_path).to match("wikis/#{path}")
- expect(page).to have_content('New Wiki Page')
- expect(page).to have_content('Create page')
+ expect(page).not_to have_xpath('/html') # Page should render the image which means there is no html involved
end
end
- context 'when a page has history' do
- before do
- wiki_page.update(message: 'updated home', content: 'updated [some link](other-page)')
- end
+ it 'shows the creation page if file does not exist' do
+ expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/#{path}")
- it 'shows the page history' do
- visit(project_wiki_path(project, wiki_page))
+ click_on('image')
- expect(page).to have_selector('a.btn', text: 'Edit')
+ expect(current_path).to match("wikis/#{path}")
+ expect(page).to have_content('New Wiki Page')
+ expect(page).to have_content('Create page')
+ end
+ end
- click_on('Page history')
+ context 'when a page has history' do
+ before do
+ wiki_page.update(message: 'updated home', content: 'updated [some link](other-page)')
+ end
- expect(page).to have_content(user.name)
- expect(page).to have_content("#{user.username} created page: home")
- expect(page).to have_content('updated home')
- end
+ it 'shows the page history' do
+ visit(project_wiki_path(project, wiki_page))
- it 'does not show the "Edit" button' do
- visit(project_wiki_path(project, wiki_page, version_id: wiki_page.versions.last.id))
+ expect(page).to have_selector('a.btn', text: 'Edit')
- expect(page).not_to have_selector('a.btn', text: 'Edit')
- end
+ click_on('Page history')
+
+ expect(page).to have_content(user.name)
+ expect(page).to have_content("#{user.username} created page: home")
+ expect(page).to have_content('updated home')
end
- context 'when page has invalid content encoding' do
- let(:content) { 'whatever'.force_encoding('ISO-8859-1') }
+ it 'does not show the "Edit" button' do
+ visit(project_wiki_path(project, wiki_page, version_id: wiki_page.versions.last.id))
- before do
- allow(Gitlab::EncodingHelper).to receive(:encode!).and_return(content)
+ expect(page).not_to have_selector('a.btn', text: 'Edit')
+ end
+ end
- visit(project_wiki_path(project, wiki_page))
- end
+ context 'when page has invalid content encoding' do
+ let(:content) { 'whatever'.force_encoding('ISO-8859-1') }
- it 'does not show "Edit" button' do
- expect(page).not_to have_selector('a.btn', text: 'Edit')
- end
+ before do
+ allow(Gitlab::EncodingHelper).to receive(:encode!).and_return(content)
- it 'shows error' do
- page.within(:css, '.flash-notice') do
- expect(page).to have_content('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.')
- end
- end
+ visit(project_wiki_path(project, wiki_page))
end
- it 'opens a default wiki page', :js do
- visit(project_path(project))
-
- find('.shortcuts-wiki').click
- click_link "Create your first page"
+ it 'does not show "Edit" button' do
+ expect(page).not_to have_selector('a.btn', text: 'Edit')
+ end
- expect(page).to have_content('Home · Create Page')
+ it 'shows error' do
+ page.within(:css, '.flash-notice') do
+ expect(page).to have_content('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.')
+ end
end
end
- context 'when Gitaly is enabled' do
- it_behaves_like 'wiki page user view'
- end
+ it 'opens a default wiki page', :js do
+ visit(project_path(project))
+
+ find('.shortcuts-wiki').click
+ click_link "Create your first page"
- context 'when Gitaly is disabled', :skip_gitaly_mock do
- it_behaves_like 'wiki page user view'
+ expect(page).to have_content('Home · Create Page')
end
end
diff --git a/spec/features/users/overview_spec.rb b/spec/features/users/overview_spec.rb
index b0ff53f9ccb..34ed771340f 100644
--- a/spec/features/users/overview_spec.rb
+++ b/spec/features/users/overview_spec.rb
@@ -54,15 +54,15 @@ describe 'Overview tab on a user profile', :js do
end
end
- describe 'user has 10 activities' do
+ describe 'user has 11 activities' do
before do
- 10.times { push_code_contribution }
+ 11.times { push_code_contribution }
end
include_context 'visit overview tab'
- it 'displays 5 entries in the list of activities' do
- expect(find('#js-overview')).to have_selector('.event-item', count: 5)
+ it 'displays 10 entries in the list of activities' do
+ expect(find('#js-overview')).to have_selector('.event-item', count: 10)
end
it 'shows a link to the activity list' do
diff --git a/spec/finders/group_descendants_finder_spec.rb b/spec/finders/group_descendants_finder_spec.rb
index c64abdc3619..c28fd7cad11 100644
--- a/spec/finders/group_descendants_finder_spec.rb
+++ b/spec/finders/group_descendants_finder_spec.rb
@@ -74,6 +74,13 @@ describe GroupDescendantsFinder do
end
end
+ it 'sorts elements by latest created as default' do
+ project1 = create(:project, namespace: group, created_at: 1.hour.ago)
+ project2 = create(:project, namespace: group)
+
+ expect(subject.execute).to eq([project2, project1])
+ end
+
context 'sorting by name' do
let!(:project1) { create(:project, namespace: group, name: 'a', path: 'project-a') }
let!(:project2) { create(:project, namespace: group, name: 'z', path: 'project-z') }
diff --git a/spec/finders/pending_todos_finder_spec.rb b/spec/finders/pending_todos_finder_spec.rb
index 32fad5e225f..b41b1b46a93 100644
--- a/spec/finders/pending_todos_finder_spec.rb
+++ b/spec/finders/pending_todos_finder_spec.rb
@@ -46,7 +46,7 @@ describe PendingTodosFinder do
create(:todo, :pending, user: user, target: note)
- todos = described_class.new(user, target_type: issue.class).execute
+ todos = described_class.new(user, target_type: issue.class.name).execute
expect(todos).to eq([todo])
end
diff --git a/spec/fixtures/authentication/saml2_response.xml b/spec/fixtures/authentication/saml2_response.xml
new file mode 100644
index 00000000000..67dea7209e9
--- /dev/null
+++ b/spec/fixtures/authentication/saml2_response.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="https://example.hello.com/access/saml" ID="jVFQbyEpSfUwqhZtJtarIaGoshwuAQMDwLoiMhzJXsv" InResponseTo="cfeooghajnhofcmogakmlhpkohnmikicnfhdnjlc" IssueInstant="2011-06-21T13:54:38.661Z" Version="2.0">
+ <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://idm.orademo.com</saml2:Issuer>
+ <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <ds:SignedInfo>
+ <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+ <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
+ <ds:Reference URI="#jVFQbyEpSfUwqhZtJtarIaGoshwuAQMDwLoiMhzJXsv">
+ <ds:Transforms>
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
+ <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
+ <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
+ </ds:Transform>
+ </ds:Transforms>
+ <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
+ <ds:DigestValue>uHuSry39P16Yh7srS32xESmj4Lw=</ds:DigestValue>
+ </ds:Reference>
+ </ds:SignedInfo>
+ <ds:SignatureValue>fdghdfggfd=</ds:SignatureValue>
+ <ds:KeyInfo>
+ <ds:X509Data>
+ <ds:X509Certificate>dfghjkl</ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </ds:Signature>
+ <saml2p:Status>
+ <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+ </saml2p:Status>
+ <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="emmCjammnYdAbMWDuMAJeZvQIMBayeeYqqwvQoDclKE" IssueInstant="2011-06-21T13:54:38.676Z" Version="2.0">
+ <saml2:Issuer>https://idm.orademo.com</saml2:Issuer>
+ <saml2:Subject>
+ <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" NameQualifier="idp.example.org">someone@example.org</saml2:NameID>
+ <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+ <saml2:SubjectConfirmationData InResponseTo="cfeooghajnhofcmogakmlhpkohnmikicnfhdnjlc" NotOnOrAfter="2011-06-21T14:09:38.676Z" Recipient="https://example.hello.com/access/saml"/>
+ </saml2:SubjectConfirmation>
+ </saml2:Subject>
+ <saml2:Conditions NotBefore="2011-06-21T13:54:38.683Z" NotOnOrAfter="2011-06-21T14:09:38.683Z">
+ <saml2:AudienceRestriction>
+ <saml2:Audience>hello.com</saml2:Audience>
+ </saml2:AudienceRestriction>
+ </saml2:Conditions>
+ <saml2:AuthnStatement AuthnInstant="2011-06-21T13:54:38.685Z" SessionIndex="perdkjfskdjfksdiertusfsdfsddeurtherukjdfgkdffg">
+ <saml2:AuthnContext>
+ <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+ </saml2:AuthnContext>
+ </saml2:AuthnStatement>
+ <saml2:AttributeStatement>
+ <saml2:Attribute Name="FirstName">
+ <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Someone</saml2:AttributeValue>
+ </saml2:Attribute>
+ <saml2:Attribute Name="LastName">
+ <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Special</saml2:AttributeValue>
+ </saml2:Attribute>
+ </saml2:AttributeStatement>
+ </saml2:Assertion>
+</saml2p:Response>
diff --git a/spec/javascripts/lib/utils/text_markdown_spec.js b/spec/javascripts/lib/utils/text_markdown_spec.js
index b9e805628f8..f71d27eb4e4 100644
--- a/spec/javascripts/lib/utils/text_markdown_spec.js
+++ b/spec/javascripts/lib/utils/text_markdown_spec.js
@@ -86,6 +86,29 @@ describe('init markdown', () => {
expect(textArea.value).toEqual(`${initialValue}* `);
});
+
+ it('places the cursor inside the tags', () => {
+ const start = 'lorem ';
+ const end = ' ipsum';
+ const tag = '*';
+
+ textArea.value = `${start}${end}`;
+ textArea.setSelectionRange(start.length, start.length);
+
+ insertMarkdownText({
+ textArea,
+ text: textArea.value,
+ tag,
+ blockTag: null,
+ selected: '',
+ wrap: true,
+ });
+
+ expect(textArea.value).toEqual(`${start}**${end}`);
+
+ // cursor placement should be between tags
+ expect(textArea.selectionStart).toBe(start.length + tag.length);
+ });
});
describe('with selection', () => {
@@ -98,16 +121,22 @@ describe('init markdown', () => {
});
it('applies the tag to the selected value', () => {
+ const selectedIndex = text.indexOf(selected);
+ const tag = '*';
+
insertMarkdownText({
textArea,
text: textArea.value,
- tag: '*',
+ tag,
blockTag: null,
selected,
wrap: true,
});
expect(textArea.value).toEqual(text.replace(selected, `*${selected}*`));
+
+ // cursor placement should be after selection + 2 tag lengths
+ expect(textArea.selectionStart).toBe(selectedIndex + selected.length + 2 * tag.length);
});
it('replaces the placeholder in the tag', () => {
diff --git a/spec/javascripts/vue_shared/components/expand_button_spec.js b/spec/javascripts/vue_shared/components/expand_button_spec.js
index 98fee9a74a5..2af4abc299a 100644
--- a/spec/javascripts/vue_shared/components/expand_button_spec.js
+++ b/spec/javascripts/vue_shared/components/expand_button_spec.js
@@ -18,7 +18,7 @@ describe('expand button', () => {
vm.$destroy();
});
- it('renders a collpased button', () => {
+ it('renders a collapsed button', () => {
expect(vm.$children[0].iconTestClass).toEqual('ic-ellipsis_h');
});
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 8947e2ac4fb..e0691aba600 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -205,28 +205,18 @@ describe ExtractsPath do
end
describe '#lfs_blob_ids' do
- shared_examples '#lfs_blob_ids' do
- let(:tag) { @project.repository.add_tag(@project.owner, 'my-annotated-tag', 'master', 'test tag') }
- let(:ref) { tag.target }
- let(:params) { { ref: ref, path: 'README.md' } }
+ let(:tag) { @project.repository.add_tag(@project.owner, 'my-annotated-tag', 'master', 'test tag') }
+ let(:ref) { tag.target }
+ let(:params) { { ref: ref, path: 'README.md' } }
- before do
- @project = create(:project, :repository)
- end
-
- it 'handles annotated tags' do
- assign_ref_vars
-
- expect(lfs_blob_ids).to eq([])
- end
+ before do
+ @project = create(:project, :repository)
end
- context 'when gitaly is enabled' do
- it_behaves_like '#lfs_blob_ids'
- end
+ it 'handles annotated tags' do
+ assign_ref_vars
- context 'when gitaly is disabled', :skip_gitaly_mock do
- it_behaves_like '#lfs_blob_ids'
+ expect(lfs_blob_ids).to eq([])
end
end
end
diff --git a/spec/lib/gitlab/auth/saml/auth_hash_spec.rb b/spec/lib/gitlab/auth/saml/auth_hash_spec.rb
index 76f49e778fb..3620e1afe25 100644
--- a/spec/lib/gitlab/auth/saml/auth_hash_spec.rb
+++ b/spec/lib/gitlab/auth/saml/auth_hash_spec.rb
@@ -82,6 +82,17 @@ describe Gitlab::Auth::Saml::AuthHash do
end
end
+ context 'with SAML 2.0 response_object' do
+ before do
+ auth_hash_data[:extra][:response_object] = { document:
+ saml_xml(File.read('spec/fixtures/authentication/saml2_response.xml')) }
+ end
+
+ it 'can extract authn_context' do
+ expect(saml_auth_hash.authn_context).to eq 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
+ end
+ end
+
context 'without response_object' do
it 'returns an empty string' do
expect(saml_auth_hash.authn_context).to be_nil
diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
index 4578da70bfc..fbcf515281e 100644
--- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
@@ -37,17 +37,7 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
let(:stub_path) { '.gitignore' }
end
- shared_examples 'initializes a DiffCollection' do
- it 'returns a valid instance of a DiffCollection' do
- expect(diff_files).to be_a(Gitlab::Git::DiffCollection)
- end
- end
-
- context 'with Gitaly disabled', :disable_gitaly do
- it_behaves_like 'initializes a DiffCollection'
- end
-
- context 'with Gitaly enabled' do
- it_behaves_like 'initializes a DiffCollection'
+ it 'returns a valid instance of a DiffCollection' do
+ expect(diff_files).to be_a(Gitlab::Git::DiffCollection)
end
end
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index b243f0dacae..80dd3dcc58e 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -128,7 +128,7 @@ describe Gitlab::Git::Blob, :seed_helper do
end
end
- shared_examples 'finding blobs by ID' do
+ describe '.raw' do
let(:raw_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::RubyBlob::ID) }
let(:bad_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::BigCommit::ID) }
@@ -166,16 +166,6 @@ describe Gitlab::Git::Blob, :seed_helper do
end
end
- describe '.raw' do
- context 'when the blob_raw Gitaly feature is enabled' do
- it_behaves_like 'finding blobs by ID'
- end
-
- context 'when the blob_raw Gitaly feature is disabled', :skip_gitaly_mock do
- it_behaves_like 'finding blobs by ID'
- end
- end
-
describe '.batch' do
let(:blob_references) do
[
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 6be35eee0fd..74d542060d5 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -183,110 +183,100 @@ describe Gitlab::Git::Commit, :seed_helper do
end
end
- shared_examples '.where' do
- context 'path is empty string' do
- subject do
- commits = described_class.where(
- repo: repository,
- ref: 'master',
- path: '',
- limit: 10
- )
-
- commits.map { |c| c.id }
- end
+ context 'path is empty string' do
+ subject do
+ commits = described_class.where(
+ repo: repository,
+ ref: 'master',
+ path: '',
+ limit: 10
+ )
- it 'has 10 elements' do
- expect(subject.size).to eq(10)
- end
- it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
+ commits.map { |c| c.id }
end
- context 'path is nil' do
- subject do
- commits = described_class.where(
- repo: repository,
- ref: 'master',
- path: nil,
- limit: 10
- )
-
- commits.map { |c| c.id }
- end
-
- it 'has 10 elements' do
- expect(subject.size).to eq(10)
- end
- it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
+ it 'has 10 elements' do
+ expect(subject.size).to eq(10)
end
+ it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
+ end
- context 'ref is branch name' do
- subject do
- commits = described_class.where(
- repo: repository,
- ref: 'master',
- path: 'files',
- limit: 3,
- offset: 1
- )
+ context 'path is nil' do
+ subject do
+ commits = described_class.where(
+ repo: repository,
+ ref: 'master',
+ path: nil,
+ limit: 10
+ )
- commits.map { |c| c.id }
- end
+ commits.map { |c| c.id }
+ end
- it 'has 3 elements' do
- expect(subject.size).to eq(3)
- end
- it { is_expected.to include("d14d6c0abdd253381df51a723d58691b2ee1ab08") }
- it { is_expected.not_to include("eb49186cfa5c4338011f5f590fac11bd66c5c631") }
+ it 'has 10 elements' do
+ expect(subject.size).to eq(10)
end
+ it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
+ end
- context 'ref is commit id' do
- subject do
- commits = described_class.where(
- repo: repository,
- ref: "874797c3a73b60d2187ed6e2fcabd289ff75171e",
- path: 'files',
- limit: 3,
- offset: 1
- )
+ context 'ref is branch name' do
+ subject do
+ commits = described_class.where(
+ repo: repository,
+ ref: 'master',
+ path: 'files',
+ limit: 3,
+ offset: 1
+ )
- commits.map { |c| c.id }
- end
+ commits.map { |c| c.id }
+ end
- it 'has 3 elements' do
- expect(subject.size).to eq(3)
- end
- it { is_expected.to include("2f63565e7aac07bcdadb654e253078b727143ec4") }
- it { is_expected.not_to include(SeedRepo::Commit::ID) }
+ it 'has 3 elements' do
+ expect(subject.size).to eq(3)
end
+ it { is_expected.to include("d14d6c0abdd253381df51a723d58691b2ee1ab08") }
+ it { is_expected.not_to include("eb49186cfa5c4338011f5f590fac11bd66c5c631") }
+ end
- context 'ref is tag' do
- subject do
- commits = described_class.where(
- repo: repository,
- ref: 'v1.0.0',
- path: 'files',
- limit: 3,
- offset: 1
- )
+ context 'ref is commit id' do
+ subject do
+ commits = described_class.where(
+ repo: repository,
+ ref: "874797c3a73b60d2187ed6e2fcabd289ff75171e",
+ path: 'files',
+ limit: 3,
+ offset: 1
+ )
- commits.map { |c| c.id }
- end
+ commits.map { |c| c.id }
+ end
- it 'has 3 elements' do
- expect(subject.size).to eq(3)
- end
- it { is_expected.to include("874797c3a73b60d2187ed6e2fcabd289ff75171e") }
- it { is_expected.not_to include(SeedRepo::Commit::ID) }
+ it 'has 3 elements' do
+ expect(subject.size).to eq(3)
end
+ it { is_expected.to include("2f63565e7aac07bcdadb654e253078b727143ec4") }
+ it { is_expected.not_to include(SeedRepo::Commit::ID) }
end
- describe '.where with gitaly' do
- it_should_behave_like '.where'
- end
+ context 'ref is tag' do
+ subject do
+ commits = described_class.where(
+ repo: repository,
+ ref: 'v1.0.0',
+ path: 'files',
+ limit: 3,
+ offset: 1
+ )
- describe '.where without gitaly', :skip_gitaly_mock do
- it_should_behave_like '.where'
+ commits.map { |c| c.id }
+ end
+
+ it 'has 3 elements' do
+ expect(subject.size).to eq(3)
+ end
+ it { is_expected.to include("874797c3a73b60d2187ed6e2fcabd289ff75171e") }
+ it { is_expected.not_to include(SeedRepo::Commit::ID) }
end
describe '.between' do
@@ -508,7 +498,7 @@ describe Gitlab::Git::Commit, :seed_helper do
end
end
- shared_examples '#stats' do
+ describe '#stats' do
subject { commit.stats }
describe '#additions' do
@@ -527,14 +517,6 @@ describe Gitlab::Git::Commit, :seed_helper do
end
end
- describe '#stats with gitaly on' do
- it_should_behave_like '#stats'
- end
-
- describe '#stats with gitaly disabled', :skip_gitaly_mock do
- it_should_behave_like '#stats'
- end
-
describe '#has_zero_stats?' do
it { expect(commit.has_zero_stats?).to eq(false) }
end
@@ -577,25 +559,15 @@ describe Gitlab::Git::Commit, :seed_helper do
commit_ids.map { |id| described_class.get_message(repository, id) }
end
- shared_examples 'getting commit messages' do
- it 'gets commit messages' do
- expect(subject).to contain_exactly(
- "Added contributing guide\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
- "Add submodule\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n"
- )
- end
- end
-
- context 'when Gitaly commit_messages feature is enabled' do
- it_behaves_like 'getting commit messages'
-
- it 'gets messages in one batch', :request_store do
- expect { subject.map(&:itself) }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
- end
+ it 'gets commit messages' do
+ expect(subject).to contain_exactly(
+ "Added contributing guide\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
+ "Add submodule\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n"
+ )
end
- context 'when Gitaly commit_messages feature is disabled', :disable_gitaly do
- it_behaves_like 'getting commit messages'
+ it 'gets messages in one batch', :request_store do
+ expect { subject.map(&:itself) }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
end
end
diff --git a/spec/lib/gitlab/git/tag_spec.rb b/spec/lib/gitlab/git/tag_spec.rb
index c5bad062c2a..abee2822d77 100644
--- a/spec/lib/gitlab/git/tag_spec.rb
+++ b/spec/lib/gitlab/git/tag_spec.rb
@@ -3,7 +3,7 @@ require "spec_helper"
describe Gitlab::Git::Tag, :seed_helper do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') }
- shared_examples 'Gitlab::Git::Repository#tags' do
+ describe '#tags' do
describe 'first tag' do
let(:tag) { repository.tags.first }
@@ -25,14 +25,6 @@ describe Gitlab::Git::Tag, :seed_helper do
it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) }
end
- context 'when Gitaly tags feature is enabled' do
- it_behaves_like 'Gitlab::Git::Repository#tags'
- end
-
- context 'when Gitaly tags feature is disabled', :skip_gitaly_mock do
- it_behaves_like 'Gitlab::Git::Repository#tags'
- end
-
describe '.get_message' do
let(:tag_ids) { %w[f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8 8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b] }
@@ -40,23 +32,13 @@ describe Gitlab::Git::Tag, :seed_helper do
tag_ids.map { |id| described_class.get_message(repository, id) }
end
- shared_examples 'getting tag messages' do
- it 'gets tag messages' do
- expect(subject[0]).to eq("Release\n")
- expect(subject[1]).to eq("Version 1.1.0\n")
- end
- end
-
- context 'when Gitaly tag_messages feature is enabled' do
- it_behaves_like 'getting tag messages'
-
- it 'gets messages in one batch', :request_store do
- expect { subject.map(&:itself) }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
- end
+ it 'gets tag messages' do
+ expect(subject[0]).to eq("Release\n")
+ expect(subject[1]).to eq("Version 1.1.0\n")
end
- context 'when Gitaly tag_messages feature is disabled', :disable_gitaly do
- it_behaves_like 'getting tag messages'
+ it 'gets messages in one batch', :request_store do
+ expect { subject.map(&:itself) }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
end
end
diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb
index 3792d6bf67b..bec875fb03d 100644
--- a/spec/lib/gitlab/git/tree_spec.rb
+++ b/spec/lib/gitlab/git/tree_spec.rb
@@ -80,18 +80,8 @@ describe Gitlab::Git::Tree, :seed_helper do
end
describe '#where' do
- shared_examples '#where' do
- it 'returns an empty array when called with an invalid ref' do
- expect(described_class.where(repository, 'foobar-does-not-exist')).to eq([])
- end
- end
-
- context 'with gitaly' do
- it_behaves_like '#where'
- end
-
- context 'without gitaly', :skip_gitaly_mock do
- it_behaves_like '#where'
+ it 'returns an empty array when called with an invalid ref' do
+ expect(described_class.where(repository, 'foobar-does-not-exist')).to eq([])
end
end
end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 81bcd8c28ed..3ae319456da 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
# We stub Gitaly in `spec/support/gitaly.rb` for other tests. We don't want
# those stubs while testing the GitalyClient itself.
-describe Gitlab::GitalyClient, skip_gitaly_mock: true do
+describe Gitlab::GitalyClient do
describe '.stub_class' do
it 'returns the gRPC health check stub' do
expect(described_class.stub_class(:health_check)).to eq(::Grpc::Health::V1::Health::Stub)
@@ -191,102 +191,13 @@ describe Gitlab::GitalyClient, skip_gitaly_mock: true do
let(:feature_name) { 'my_feature' }
let(:real_feature_name) { "gitaly_#{feature_name}" }
- context 'when Gitaly is disabled' do
- before do
- allow(described_class).to receive(:enabled?).and_return(false)
- end
-
- it 'returns false' do
- expect(described_class.feature_enabled?(feature_name)).to be(false)
- end
- end
-
- context 'when the feature status is DISABLED' do
- let(:feature_status) { Gitlab::GitalyClient::MigrationStatus::DISABLED }
-
- it 'returns false' do
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
- end
- end
-
- context 'when the feature_status is OPT_IN' do
- let(:feature_status) { Gitlab::GitalyClient::MigrationStatus::OPT_IN }
-
- context "when the feature flag hasn't been set" do
- it 'returns false' do
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
- end
- end
-
- context "when the feature flag is set to disable" do
- before do
- Feature.get(real_feature_name).disable
- end
-
- it 'returns false' do
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
- end
- end
-
- context "when the feature flag is set to enable" do
- before do
- Feature.get(real_feature_name).enable
- end
-
- it 'returns true' do
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
- end
- end
-
- context "when the feature flag is set to a percentage of time" do
- before do
- Feature.get(real_feature_name).enable_percentage_of_time(70)
- end
-
- it 'bases the result on pseudo-random numbers' do
- expect(Random).to receive(:rand).and_return(0.3)
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
-
- expect(Random).to receive(:rand).and_return(0.8)
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
- end
- end
-
- context "when a feature is not persisted" do
- it 'returns false when opt_into_all_features is off' do
- allow(Feature).to receive(:persisted?).and_return(false)
- allow(described_class).to receive(:opt_into_all_features?).and_return(false)
-
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
- end
-
- it 'returns true when the override is on' do
- allow(Feature).to receive(:persisted?).and_return(false)
- allow(described_class).to receive(:opt_into_all_features?).and_return(true)
-
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
- end
- end
+ before do
+ allow(Feature).to receive(:enabled?).and_return(false)
end
- context 'when the feature_status is OPT_OUT' do
- let(:feature_status) { Gitlab::GitalyClient::MigrationStatus::OPT_OUT }
-
- context "when the feature flag hasn't been set" do
- it 'returns true' do
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
- end
- end
-
- context "when the feature flag is set to disable" do
- before do
- Feature.get(real_feature_name).disable
- end
-
- it 'returns false' do
- expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
- end
- end
+ it 'returns false' do
+ expect(Feature).to receive(:enabled?).with(real_feature_name)
+ expect(described_class.feature_enabled?(feature_name)).to be(false)
end
end
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 3f2281f213f..58949f76bd6 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -2556,7 +2556,7 @@
"merge_request_diff_id": 27,
"relative_order": 0,
"sha": "bb5206fee213d983da88c47f9cf4cc6caf9c66dc",
- "message": "Feature conflcit added\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
+ "message": "Feature conflict added\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-08-06T08:35:52.000+02:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -3605,7 +3605,7 @@
"merge_request_diff_id": 14,
"relative_order": 8,
"sha": "08f22f255f082689c0d7d39d19205085311542bc",
- "message": "remove emtpy file.(beacase git ignore empty file)\nadd whitespace test file.\n",
+ "message": "remove empty file.(beacase git ignore empty file)\nadd whitespace test file.\n",
"authored_date": "2015-11-13T06:00:16.000+01:00",
"author_name": "윤민식",
"author_email": "minsik.yoon@samsung.com",
@@ -4290,7 +4290,7 @@
"merge_request_diff_id": 13,
"relative_order": 8,
"sha": "08f22f255f082689c0d7d39d19205085311542bc",
- "message": "remove emtpy file.(beacase git ignore empty file)\nadd whitespace test file.\n",
+ "message": "remove empty file.(beacase git ignore empty file)\nadd whitespace test file.\n",
"authored_date": "2015-11-13T06:00:16.000+01:00",
"author_name": "윤민식",
"author_email": "minsik.yoon@samsung.com",
@@ -4799,7 +4799,7 @@
"merge_request_diff_id": 12,
"relative_order": 8,
"sha": "08f22f255f082689c0d7d39d19205085311542bc",
- "message": "remove emtpy file.(beacase git ignore empty file)\nadd whitespace test file.\n",
+ "message": "remove empty file.(beacase git ignore empty file)\nadd whitespace test file.\n",
"authored_date": "2015-11-13T06:00:16.000+01:00",
"author_name": "윤민식",
"author_email": "minsik.yoon@samsung.com",
@@ -5507,7 +5507,7 @@
"merge_request_diff_id": 10,
"relative_order": 8,
"sha": "08f22f255f082689c0d7d39d19205085311542bc",
- "message": "remove emtpy file.(beacase git ignore empty file)\nadd whitespace test file.\n",
+ "message": "remove empty file.(beacase git ignore empty file)\nadd whitespace test file.\n",
"authored_date": "2015-11-13T06:00:16.000+01:00",
"author_name": "윤민식",
"author_email": "minsik.yoon@samsung.com",
diff --git a/spec/lib/gitlab/import_export/project.light.json b/spec/lib/gitlab/import_export/project.light.json
index ba2248073f5..2971ca0f0f8 100644
--- a/spec/lib/gitlab/import_export/project.light.json
+++ b/spec/lib/gitlab/import_export/project.light.json
@@ -101,6 +101,28 @@
]
}
],
+ "services": [
+ {
+ "id": 100,
+ "title": "JetBrains TeamCity CI",
+ "project_id": 5,
+ "created_at": "2016-06-14T15:01:51.315Z",
+ "updated_at": "2016-06-14T15:01:51.315Z",
+ "active": false,
+ "properties": {},
+ "template": true,
+ "push_events": true,
+ "issues_events": true,
+ "merge_requests_events": true,
+ "tag_push_events": true,
+ "note_events": true,
+ "job_events": true,
+ "type": "TeamcityService",
+ "category": "ci",
+ "default": false,
+ "wiki_page_events": true
+ }
+ ],
"snippets": [],
"hooks": []
}
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 365bfae0d88..7171e12a849 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -297,7 +297,8 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
issues: 1,
labels: 1,
milestones: 1,
- first_issue_labels: 1
+ first_issue_labels: 1,
+ services: 1
context 'project.json file access check' do
it 'does not read a symlink' do
@@ -382,6 +383,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
project_tree_restorer.instance_variable_set(:@path, "spec/lib/gitlab/import_export/project.light.json")
end
+ it 'does not import any templated services' do
+ restored_project_json
+
+ expect(project.services.where(template: true).count).to eq(0)
+ end
+
it 'imports labels' do
create(:group_label, name: 'Another label', group: project.group)
diff --git a/spec/lib/gitlab/repository_cache_spec.rb b/spec/lib/gitlab/repository_cache_spec.rb
index 741ee12633f..1b9a8b4ab0d 100644
--- a/spec/lib/gitlab/repository_cache_spec.rb
+++ b/spec/lib/gitlab/repository_cache_spec.rb
@@ -4,14 +4,14 @@ describe Gitlab::RepositoryCache do
let(:backend) { double('backend').as_null_object }
let(:project) { create(:project) }
let(:repository) { project.repository }
- let(:namespace) { "#{repository.full_path}:#{project.id}" }
+ let(:namespace) { "project:#{project.id}" }
let(:cache) { described_class.new(repository, backend: backend) }
describe '#cache_key' do
subject { cache.cache_key(:foo) }
it 'includes the namespace' do
- expect(subject).to eq "foo:#{namespace}"
+ expect(subject).to eq "#{namespace}:foo"
end
context 'with a given namespace' do
@@ -22,7 +22,7 @@ describe Gitlab::RepositoryCache do
end
it 'includes the full namespace' do
- expect(subject).to eq "foo:#{namespace}:#{extra_namespace}"
+ expect(subject).to eq "#{namespace}:#{extra_namespace}:foo"
end
end
end
@@ -30,21 +30,21 @@ describe Gitlab::RepositoryCache do
describe '#expire' do
it 'expires the given key from the cache' do
cache.expire(:foo)
- expect(backend).to have_received(:delete).with("foo:#{namespace}")
+ expect(backend).to have_received(:delete).with("#{namespace}:foo")
end
end
describe '#fetch' do
it 'fetches the given key from the cache' do
cache.fetch(:bar)
- expect(backend).to have_received(:fetch).with("bar:#{namespace}")
+ expect(backend).to have_received(:fetch).with("#{namespace}:bar")
end
it 'accepts a block' do
p = -> {}
cache.fetch(:baz, &p)
- expect(backend).to have_received(:fetch).with("baz:#{namespace}", &p)
+ expect(backend).to have_received(:fetch).with("#{namespace}:baz", &p)
end
end
@@ -67,7 +67,7 @@ describe Gitlab::RepositoryCache do
end
it 'caches the value' do
- expect(backend).to receive(:write).with("#{key}:#{namespace}", true)
+ expect(backend).to receive(:write).with("#{namespace}:#{key}", true)
cache.fetch_without_caching_false(key) { true }
end
@@ -83,7 +83,7 @@ describe Gitlab::RepositoryCache do
end
it 'does not cache the value' do
- expect(backend).not_to receive(:write).with("#{key}:#{namespace}", true)
+ expect(backend).not_to receive(:write).with("#{namespace}:#{key}", true)
cache.fetch_without_caching_false(key, &p)
end
@@ -92,7 +92,7 @@ describe Gitlab::RepositoryCache do
context 'when the cached value is truthy' do
before do
- backend.write("#{key}:#{namespace}", true)
+ backend.write("#{namespace}:#{key}", true)
end
it 'returns the cached value' do
@@ -116,7 +116,7 @@ describe Gitlab::RepositoryCache do
context 'when the cached value is falsey' do
before do
- backend.write("#{key}:#{namespace}", false)
+ backend.write("#{namespace}:#{key}", false)
end
it 'returns the result of the block' do
@@ -126,7 +126,7 @@ describe Gitlab::RepositoryCache do
end
it 'writes the truthy value to the cache' do
- expect(backend).to receive(:write).with("#{key}:#{namespace}", 'block result')
+ expect(backend).to receive(:write).with("#{namespace}:#{key}", 'block result')
cache.fetch_without_caching_false(key) { 'block result' }
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index a58dc8e25e8..ad55c280399 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -30,48 +30,38 @@ describe MergeRequest do
end
describe '#squash_in_progress?' do
- shared_examples 'checking whether a squash is in progress' do
- let(:repo_path) do
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- subject.source_project.repository.path
- end
- end
- let(:squash_path) { File.join(repo_path, "gitlab-worktree", "squash-#{subject.id}") }
-
- before do
- system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} worktree add --detach #{squash_path} master))
- end
-
- it 'returns true when there is a current squash directory' do
- expect(subject.squash_in_progress?).to be_truthy
+ let(:repo_path) do
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ subject.source_project.repository.path
end
+ end
+ let(:squash_path) { File.join(repo_path, "gitlab-worktree", "squash-#{subject.id}") }
- it 'returns false when there is no squash directory' do
- FileUtils.rm_rf(squash_path)
+ before do
+ system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} worktree add --detach #{squash_path} master))
+ end
- expect(subject.squash_in_progress?).to be_falsey
- end
+ it 'returns true when there is a current squash directory' do
+ expect(subject.squash_in_progress?).to be_truthy
+ end
- it 'returns false when the squash directory has expired' do
- time = 20.minutes.ago.to_time
- File.utime(time, time, squash_path)
+ it 'returns false when there is no squash directory' do
+ FileUtils.rm_rf(squash_path)
- expect(subject.squash_in_progress?).to be_falsey
- end
+ expect(subject.squash_in_progress?).to be_falsey
+ end
- it 'returns false when the source project has been removed' do
- allow(subject).to receive(:source_project).and_return(nil)
+ it 'returns false when the squash directory has expired' do
+ time = 20.minutes.ago.to_time
+ File.utime(time, time, squash_path)
- expect(subject.squash_in_progress?).to be_falsey
- end
+ expect(subject.squash_in_progress?).to be_falsey
end
- context 'when Gitaly squash_in_progress is enabled' do
- it_behaves_like 'checking whether a squash is in progress'
- end
+ it 'returns false when the source project has been removed' do
+ allow(subject).to receive(:source_project).and_return(nil)
- context 'when Gitaly squash_in_progress is disabled', :disable_gitaly do
- it_behaves_like 'checking whether a squash is in progress'
+ expect(subject.squash_in_progress?).to be_falsey
end
end
@@ -2587,14 +2577,6 @@ describe MergeRequest do
expect(subject.rebase_in_progress?).to be_falsey
end
end
-
- context 'when Gitaly rebase_in_progress is enabled' do
- it_behaves_like 'checking whether a rebase is in progress'
- end
-
- context 'when Gitaly rebase_in_progress is enabled', :disable_gitaly do
- it_behaves_like 'checking whether a rebase is in progress'
- end
end
describe '#allow_collaboration' do
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index cc5e34782ec..48a43801b9f 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -130,63 +130,53 @@ describe ProjectWiki do
end
describe "#find_page" do
- shared_examples 'finding a wiki page' do
- before do
- create_page("index page", "This is an awesome Gollum Wiki")
- end
-
- after do
- subject.pages.each { |page| destroy_page(page.page) }
- end
+ before do
+ create_page("index page", "This is an awesome Gollum Wiki")
+ end
- it "returns the latest version of the page if it exists" do
- page = subject.find_page("index page")
- expect(page.title).to eq("index page")
- end
+ after do
+ subject.pages.each { |page| destroy_page(page.page) }
+ end
- it "returns nil if the page does not exist" do
- expect(subject.find_page("non-existent")).to eq(nil)
- end
+ it "returns the latest version of the page if it exists" do
+ page = subject.find_page("index page")
+ expect(page.title).to eq("index page")
+ end
- it "can find a page by slug" do
- page = subject.find_page("index-page")
- expect(page.title).to eq("index page")
- end
+ it "returns nil if the page does not exist" do
+ expect(subject.find_page("non-existent")).to eq(nil)
+ end
- it "returns a WikiPage instance" do
- page = subject.find_page("index page")
- expect(page).to be_a WikiPage
- end
+ it "can find a page by slug" do
+ page = subject.find_page("index-page")
+ expect(page.title).to eq("index page")
+ end
- context 'pages with multibyte-character title' do
- before do
- create_page("autre pagé", "C'est un génial Gollum Wiki")
- end
+ it "returns a WikiPage instance" do
+ page = subject.find_page("index page")
+ expect(page).to be_a WikiPage
+ end
- it "can find a page by slug" do
- page = subject.find_page("autre pagé")
- expect(page.title).to eq("autre pagé")
- end
+ context 'pages with multibyte-character title' do
+ before do
+ create_page("autre pagé", "C'est un génial Gollum Wiki")
end
- context 'pages with invalidly-encoded content' do
- before do
- create_page("encoding is fun", "f\xFCr".b)
- end
-
- it "can find the page" do
- page = subject.find_page("encoding is fun")
- expect(page.content).to eq("fr")
- end
+ it "can find a page by slug" do
+ page = subject.find_page("autre pagé")
+ expect(page.title).to eq("autre pagé")
end
end
- context 'when Gitaly wiki_find_page is enabled' do
- it_behaves_like 'finding a wiki page'
- end
+ context 'pages with invalidly-encoded content' do
+ before do
+ create_page("encoding is fun", "f\xFCr".b)
+ end
- context 'when Gitaly wiki_find_page is disabled', :skip_gitaly_mock do
- it_behaves_like 'finding a wiki page'
+ it "can find the page" do
+ page = subject.find_page("encoding is fun")
+ expect(page.content).to eq("fr")
+ end
end
end
@@ -207,100 +197,80 @@ describe ProjectWiki do
end
describe '#find_file' do
- shared_examples 'finding a wiki file' do
- let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) }
-
- before do
- subject.wiki # Make sure the wiki repo exists
-
- repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- subject.repository.path_to_repo
- end
-
- BareRepoOperations.new(repo_path).commit_file(image, 'image.png')
- end
+ let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) }
- it 'returns the latest version of the file if it exists' do
- file = subject.find_file('image.png')
- expect(file.mime_type).to eq('image/png')
- end
+ before do
+ subject.wiki # Make sure the wiki repo exists
- it 'returns nil if the page does not exist' do
- expect(subject.find_file('non-existent')).to eq(nil)
+ repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ subject.repository.path_to_repo
end
- it 'returns a Gitlab::Git::WikiFile instance' do
- file = subject.find_file('image.png')
- expect(file).to be_a Gitlab::Git::WikiFile
- end
+ BareRepoOperations.new(repo_path).commit_file(image, 'image.png')
+ end
- it 'returns the whole file' do
- file = subject.find_file('image.png')
- image.rewind
+ it 'returns the latest version of the file if it exists' do
+ file = subject.find_file('image.png')
+ expect(file.mime_type).to eq('image/png')
+ end
- expect(file.raw_data.b).to eq(image.read.b)
- end
+ it 'returns nil if the page does not exist' do
+ expect(subject.find_file('non-existent')).to eq(nil)
end
- context 'when Gitaly wiki_find_file is enabled' do
- it_behaves_like 'finding a wiki file'
+ it 'returns a Gitlab::Git::WikiFile instance' do
+ file = subject.find_file('image.png')
+ expect(file).to be_a Gitlab::Git::WikiFile
end
- context 'when Gitaly wiki_find_file is disabled', :skip_gitaly_mock do
- it_behaves_like 'finding a wiki file'
+ it 'returns the whole file' do
+ file = subject.find_file('image.png')
+ image.rewind
+
+ expect(file.raw_data.b).to eq(image.read.b)
end
end
describe "#create_page" do
- shared_examples 'creating a wiki page' do
- after do
- destroy_page(subject.pages.first.page)
- end
-
- it "creates a new wiki page" do
- expect(subject.create_page("test page", "this is content")).not_to eq(false)
- expect(subject.pages.count).to eq(1)
- end
-
- it "returns false when a duplicate page exists" do
- subject.create_page("test page", "content")
- expect(subject.create_page("test page", "content")).to eq(false)
- end
-
- it "stores an error message when a duplicate page exists" do
- 2.times { subject.create_page("test page", "content") }
- expect(subject.error_message).to match(/Duplicate page:/)
- end
+ after do
+ destroy_page(subject.pages.first.page)
+ end
- it "sets the correct commit message" do
- subject.create_page("test page", "some content", :markdown, "commit message")
- expect(subject.pages.first.page.version.message).to eq("commit message")
- end
+ it "creates a new wiki page" do
+ expect(subject.create_page("test page", "this is content")).not_to eq(false)
+ expect(subject.pages.count).to eq(1)
+ end
- it 'sets the correct commit email' do
- subject.create_page('test page', 'content')
+ it "returns false when a duplicate page exists" do
+ subject.create_page("test page", "content")
+ expect(subject.create_page("test page", "content")).to eq(false)
+ end
- expect(user.commit_email).not_to eq(user.email)
- expect(commit.author_email).to eq(user.commit_email)
- expect(commit.committer_email).to eq(user.commit_email)
- end
+ it "stores an error message when a duplicate page exists" do
+ 2.times { subject.create_page("test page", "content") }
+ expect(subject.error_message).to match(/Duplicate page:/)
+ end
- it 'updates project activity' do
- subject.create_page('Test Page', 'This is content')
+ it "sets the correct commit message" do
+ subject.create_page("test page", "some content", :markdown, "commit message")
+ expect(subject.pages.first.page.version.message).to eq("commit message")
+ end
- project.reload
+ it 'sets the correct commit email' do
+ subject.create_page('test page', 'content')
- expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
- expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
- end
+ expect(user.commit_email).not_to eq(user.email)
+ expect(commit.author_email).to eq(user.commit_email)
+ expect(commit.committer_email).to eq(user.commit_email)
end
- context 'when Gitaly wiki_write_page is enabled' do
- it_behaves_like 'creating a wiki page'
- end
+ it 'updates project activity' do
+ subject.create_page('Test Page', 'This is content')
- context 'when Gitaly wiki_write_page is disabled', :skip_gitaly_mock do
- it_behaves_like 'creating a wiki page'
+ project.reload
+
+ expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
+ expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end
end
@@ -351,41 +321,31 @@ describe ProjectWiki do
end
describe "#delete_page" do
- shared_examples 'deleting a wiki page' do
- before do
- create_page("index", "some content")
- @page = subject.wiki.page(title: "index")
- end
-
- it "deletes the page" do
- subject.delete_page(@page)
- expect(subject.pages.count).to eq(0)
- end
-
- it 'sets the correct commit email' do
- subject.delete_page(@page)
-
- expect(user.commit_email).not_to eq(user.email)
- expect(commit.author_email).to eq(user.commit_email)
- expect(commit.committer_email).to eq(user.commit_email)
- end
+ before do
+ create_page("index", "some content")
+ @page = subject.wiki.page(title: "index")
+ end
- it 'updates project activity' do
- subject.delete_page(@page)
+ it "deletes the page" do
+ subject.delete_page(@page)
+ expect(subject.pages.count).to eq(0)
+ end
- project.reload
+ it 'sets the correct commit email' do
+ subject.delete_page(@page)
- expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
- expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
- end
+ expect(user.commit_email).not_to eq(user.email)
+ expect(commit.author_email).to eq(user.commit_email)
+ expect(commit.committer_email).to eq(user.commit_email)
end
- context 'when Gitaly wiki_delete_page is enabled' do
- it_behaves_like 'deleting a wiki page'
- end
+ it 'updates project activity' do
+ subject.delete_page(@page)
+
+ project.reload
- context 'when Gitaly wiki_delete_page is disabled', :skip_gitaly_mock do
- it_behaves_like 'deleting a wiki page'
+ expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
+ expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 799a60ac62f..187283b284b 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -38,49 +38,29 @@ describe Repository do
end
describe '#branch_names_contains' do
- shared_examples '#branch_names_contains' do
- set(:project) { create(:project, :repository) }
- let(:repository) { project.repository }
+ set(:project) { create(:project, :repository) }
+ let(:repository) { project.repository }
- subject { repository.branch_names_contains(sample_commit.id) }
+ subject { repository.branch_names_contains(sample_commit.id) }
- it { is_expected.to include('master') }
- it { is_expected.not_to include('feature') }
- it { is_expected.not_to include('fix') }
+ it { is_expected.to include('master') }
+ it { is_expected.not_to include('feature') }
+ it { is_expected.not_to include('fix') }
- describe 'when storage is broken', :broken_storage do
- it 'should raise a storage error' do
- expect_to_raise_storage_error do
- broken_repository.branch_names_contains(sample_commit.id)
- end
+ describe 'when storage is broken', :broken_storage do
+ it 'should raise a storage error' do
+ expect_to_raise_storage_error do
+ broken_repository.branch_names_contains(sample_commit.id)
end
end
end
-
- context 'when gitaly is enabled' do
- it_behaves_like '#branch_names_contains'
- end
-
- context 'when gitaly is disabled', :skip_gitaly_mock do
- it_behaves_like '#branch_names_contains'
- end
end
describe '#tag_names_contains' do
- shared_examples '#tag_names_contains' do
- subject { repository.tag_names_contains(sample_commit.id) }
-
- it { is_expected.to include('v1.1.0') }
- it { is_expected.not_to include('v1.0.0') }
- end
-
- context 'when gitaly is enabled' do
- it_behaves_like '#tag_names_contains'
- end
+ subject { repository.tag_names_contains(sample_commit.id) }
- context 'when gitaly is enabled', :skip_gitaly_mock do
- it_behaves_like '#tag_names_contains'
- end
+ it { is_expected.to include('v1.1.0') }
+ it { is_expected.not_to include('v1.0.0') }
end
describe 'tags_sorted_by' do
@@ -238,61 +218,41 @@ describe Repository do
end
describe '#last_commit_for_path' do
- shared_examples 'getting last commit for path' do
- subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id }
+ subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id }
- it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
+ it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
- describe 'when storage is broken', :broken_storage do
- it 'should raise a storage error' do
- expect_to_raise_storage_error do
- broken_repository.last_commit_id_for_path(sample_commit.id, '.gitignore')
- end
+ describe 'when storage is broken', :broken_storage do
+ it 'should raise a storage error' do
+ expect_to_raise_storage_error do
+ broken_repository.last_commit_id_for_path(sample_commit.id, '.gitignore')
end
end
end
-
- context 'when Gitaly feature last_commit_for_path is enabled' do
- it_behaves_like 'getting last commit for path'
- end
-
- context 'when Gitaly feature last_commit_for_path is disabled', :skip_gitaly_mock do
- it_behaves_like 'getting last commit for path'
- end
end
describe '#last_commit_id_for_path' do
- shared_examples 'getting last commit ID for path' do
- subject { repository.last_commit_id_for_path(sample_commit.id, '.gitignore') }
+ subject { repository.last_commit_id_for_path(sample_commit.id, '.gitignore') }
- it "returns last commit id for a given path" do
- is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8')
- end
+ it "returns last commit id for a given path" do
+ is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8')
+ end
- it "caches last commit id for a given path" do
- cache = repository.send(:cache)
- key = "last_commit_id_for_path:#{sample_commit.id}:#{Digest::SHA1.hexdigest('.gitignore')}"
+ it "caches last commit id for a given path" do
+ cache = repository.send(:cache)
+ key = "last_commit_id_for_path:#{sample_commit.id}:#{Digest::SHA1.hexdigest('.gitignore')}"
- expect(cache).to receive(:fetch).with(key).and_return('c1acaa5')
- is_expected.to eq('c1acaa5')
- end
+ expect(cache).to receive(:fetch).with(key).and_return('c1acaa5')
+ is_expected.to eq('c1acaa5')
+ end
- describe 'when storage is broken', :broken_storage do
- it 'should raise a storage error' do
- expect_to_raise_storage_error do
- broken_repository.last_commit_for_path(sample_commit.id, '.gitignore').id
- end
+ describe 'when storage is broken', :broken_storage do
+ it 'should raise a storage error' do
+ expect_to_raise_storage_error do
+ broken_repository.last_commit_for_path(sample_commit.id, '.gitignore').id
end
end
end
-
- context 'when Gitaly feature last_commit_for_path is enabled' do
- it_behaves_like 'getting last commit ID for path'
- end
-
- context 'when Gitaly feature last_commit_for_path is disabled', :skip_gitaly_mock do
- it_behaves_like 'getting last commit ID for path'
- end
end
describe '#commits' do
@@ -374,78 +334,57 @@ describe Repository do
describe '#commits_by' do
set(:project) { create(:project, :repository) }
+ let(:oids) { TestEnv::BRANCH_SHA.values }
- shared_examples 'batch commits fetching' do
- let(:oids) { TestEnv::BRANCH_SHA.values }
+ subject { project.repository.commits_by(oids: oids) }
- subject { project.repository.commits_by(oids: oids) }
+ it 'finds each commit' do
+ expect(subject).not_to include(nil)
+ expect(subject.size).to eq(oids.size)
+ end
- it 'finds each commit' do
- expect(subject).not_to include(nil)
- expect(subject.size).to eq(oids.size)
- end
+ it 'returns only Commit instances' do
+ expect(subject).to all( be_a(Commit) )
+ end
- it 'returns only Commit instances' do
- expect(subject).to all( be_a(Commit) )
+ context 'when some commits are not found ' do
+ let(:oids) do
+ ['deadbeef'] + TestEnv::BRANCH_SHA.values.first(10)
end
- context 'when some commits are not found ' do
- let(:oids) do
- ['deadbeef'] + TestEnv::BRANCH_SHA.values.first(10)
- end
-
- it 'returns only found commits' do
- expect(subject).not_to include(nil)
- expect(subject.size).to eq(10)
- end
+ it 'returns only found commits' do
+ expect(subject).not_to include(nil)
+ expect(subject.size).to eq(10)
end
+ end
- context 'when no oids are passed' do
- let(:oids) { [] }
+ context 'when no oids are passed' do
+ let(:oids) { [] }
- it 'does not call #batch_by_oid' do
- expect(Gitlab::Git::Commit).not_to receive(:batch_by_oid)
+ it 'does not call #batch_by_oid' do
+ expect(Gitlab::Git::Commit).not_to receive(:batch_by_oid)
- subject
- end
+ subject
end
end
-
- context 'when Gitaly list_commits_by_oid is enabled' do
- it_behaves_like 'batch commits fetching'
- end
-
- context 'when Gitaly list_commits_by_oid is enabled', :disable_gitaly do
- it_behaves_like 'batch commits fetching'
- end
end
describe '#find_commits_by_message' do
- shared_examples 'finding commits by message' do
- it 'returns commits with messages containing a given string' do
- commit_ids = repository.find_commits_by_message('submodule').map(&:id)
+ it 'returns commits with messages containing a given string' do
+ commit_ids = repository.find_commits_by_message('submodule').map(&:id)
- expect(commit_ids).to include(
- '5937ac0a7beb003549fc5fd26fc247adbce4a52e',
- '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9',
- 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660'
- )
- expect(commit_ids).not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e')
- end
-
- it 'is case insensitive' do
- commit_ids = repository.find_commits_by_message('SUBMODULE').map(&:id)
-
- expect(commit_ids).to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
- end
+ expect(commit_ids).to include(
+ '5937ac0a7beb003549fc5fd26fc247adbce4a52e',
+ '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9',
+ 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660'
+ )
+ expect(commit_ids).not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e')
end
- context 'when Gitaly commits_by_message feature is enabled' do
- it_behaves_like 'finding commits by message'
- end
+ it 'is case insensitive' do
+ commit_ids = repository.find_commits_by_message('SUBMODULE').map(&:id)
- context 'when Gitaly commits_by_message feature is disabled', :skip_gitaly_mock do
- it_behaves_like 'finding commits by message'
+ expect(commit_ids).to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
end
describe 'when storage is broken', :broken_storage do
@@ -1328,34 +1267,23 @@ describe Repository do
describe '#merge' do
let(:merge_request) { create(:merge_request, source_branch: 'feature', target_branch: 'master', source_project: project) }
-
let(:message) { 'Test \r\n\r\n message' }
- shared_examples '#merge' do
- it 'merges the code and returns the commit id' do
- expect(merge_commit).to be_present
- expect(repository.blob_at(merge_commit.id, 'files/ruby/feature.rb')).to be_present
- end
-
- it 'sets the `in_progress_merge_commit_sha` flag for the given merge request' do
- merge_commit_id = merge(repository, user, merge_request, message)
-
- expect(merge_request.in_progress_merge_commit_sha).to eq(merge_commit_id)
- end
+ it 'merges the code and returns the commit id' do
+ expect(merge_commit).to be_present
+ expect(repository.blob_at(merge_commit.id, 'files/ruby/feature.rb')).to be_present
+ end
- it 'removes carriage returns from commit message' do
- merge_commit_id = merge(repository, user, merge_request, message)
+ it 'sets the `in_progress_merge_commit_sha` flag for the given merge request' do
+ merge_commit_id = merge(repository, user, merge_request, message)
- expect(repository.commit(merge_commit_id).message).to eq(message.delete("\r"))
- end
+ expect(merge_request.in_progress_merge_commit_sha).to eq(merge_commit_id)
end
- context 'with gitaly' do
- it_behaves_like '#merge'
- end
+ it 'removes carriage returns from commit message' do
+ merge_commit_id = merge(repository, user, merge_request, message)
- context 'without gitaly', :skip_gitaly_mock do
- it_behaves_like '#merge'
+ expect(repository.commit(merge_commit_id).message).to eq(message.delete("\r"))
end
def merge(repository, user, merge_request, message)
@@ -1392,98 +1320,78 @@ describe Repository do
end
describe '#revert' do
- shared_examples 'reverting a commit' do
- let(:new_image_commit) { repository.commit('33f3729a45c02fc67d00adb1b8bca394b0e761d9') }
- let(:update_image_commit) { repository.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
- let(:message) { 'revert message' }
-
- context 'when there is a conflict' do
- it 'raises an error' do
- expect { repository.revert(user, new_image_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
- end
- end
+ let(:new_image_commit) { repository.commit('33f3729a45c02fc67d00adb1b8bca394b0e761d9') }
+ let(:update_image_commit) { repository.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
+ let(:message) { 'revert message' }
- context 'when commit was already reverted' do
- it 'raises an error' do
- repository.revert(user, update_image_commit, 'master', message)
-
- expect { repository.revert(user, update_image_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
- end
- end
-
- context 'when commit can be reverted' do
- it 'reverts the changes' do
- expect(repository.revert(user, update_image_commit, 'master', message)).to be_truthy
- end
+ context 'when there is a conflict' do
+ it 'raises an error' do
+ expect { repository.revert(user, new_image_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
+ end
- context 'reverting a merge commit' do
- it 'reverts the changes' do
- merge_commit
- expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).to be_present
+ context 'when commit was already reverted' do
+ it 'raises an error' do
+ repository.revert(user, update_image_commit, 'master', message)
- repository.revert(user, merge_commit, 'master', message)
- expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).not_to be_present
- end
+ expect { repository.revert(user, update_image_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
end
- context 'when Gitaly revert feature is enabled' do
- it_behaves_like 'reverting a commit'
+ context 'when commit can be reverted' do
+ it 'reverts the changes' do
+ expect(repository.revert(user, update_image_commit, 'master', message)).to be_truthy
+ end
end
- context 'when Gitaly revert feature is disabled', :disable_gitaly do
- it_behaves_like 'reverting a commit'
+ context 'reverting a merge commit' do
+ it 'reverts the changes' do
+ merge_commit
+ expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).to be_present
+
+ repository.revert(user, merge_commit, 'master', message)
+ expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).not_to be_present
+ end
end
end
describe '#cherry_pick' do
- shared_examples 'cherry-picking a commit' do
- let(:conflict_commit) { repository.commit('c642fe9b8b9f28f9225d7ea953fe14e74748d53b') }
- let(:pickable_commit) { repository.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
- let(:pickable_merge) { repository.commit('e56497bb5f03a90a51293fc6d516788730953899') }
- let(:message) { 'cherry-pick message' }
-
- context 'when there is a conflict' do
- it 'raises an error' do
- expect { repository.cherry_pick(user, conflict_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
- end
+ let(:conflict_commit) { repository.commit('c642fe9b8b9f28f9225d7ea953fe14e74748d53b') }
+ let(:pickable_commit) { repository.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
+ let(:pickable_merge) { repository.commit('e56497bb5f03a90a51293fc6d516788730953899') }
+ let(:message) { 'cherry-pick message' }
+
+ context 'when there is a conflict' do
+ it 'raises an error' do
+ expect { repository.cherry_pick(user, conflict_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
+ end
- context 'when commit was already cherry-picked' do
- it 'raises an error' do
- repository.cherry_pick(user, pickable_commit, 'master', message)
+ context 'when commit was already cherry-picked' do
+ it 'raises an error' do
+ repository.cherry_pick(user, pickable_commit, 'master', message)
- expect { repository.cherry_pick(user, pickable_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
- end
+ expect { repository.cherry_pick(user, pickable_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
+ end
- context 'when commit can be cherry-picked' do
- it 'cherry-picks the changes' do
- expect(repository.cherry_pick(user, pickable_commit, 'master', message)).to be_truthy
- end
+ context 'when commit can be cherry-picked' do
+ it 'cherry-picks the changes' do
+ expect(repository.cherry_pick(user, pickable_commit, 'master', message)).to be_truthy
end
+ end
- context 'cherry-picking a merge commit' do
- it 'cherry-picks the changes' do
- expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).to be_nil
+ context 'cherry-picking a merge commit' do
+ it 'cherry-picks the changes' do
+ expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).to be_nil
- cherry_pick_commit_sha = repository.cherry_pick(user, pickable_merge, 'improve/awesome', message)
- cherry_pick_commit_message = project.commit(cherry_pick_commit_sha).message
+ cherry_pick_commit_sha = repository.cherry_pick(user, pickable_merge, 'improve/awesome', message)
+ cherry_pick_commit_message = project.commit(cherry_pick_commit_sha).message
- expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).not_to be_nil
- expect(cherry_pick_commit_message).to eq(message)
- end
+ expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).not_to be_nil
+ expect(cherry_pick_commit_message).to eq(message)
end
end
-
- context 'when Gitaly cherry_pick feature is enabled' do
- it_behaves_like 'cherry-picking a commit'
- end
-
- context 'when Gitaly cherry_pick feature is disabled', :disable_gitaly do
- it_behaves_like 'cherry-picking a commit'
- end
end
describe '#before_delete' do
@@ -2190,33 +2098,23 @@ describe Repository do
let(:commit) { repository.commit }
let(:ancestor) { commit.parents.first }
- shared_examples '#ancestor?' do
- it 'it is an ancestor' do
- expect(repository.ancestor?(ancestor.id, commit.id)).to eq(true)
- end
-
- it 'it is not an ancestor' do
- expect(repository.ancestor?(commit.id, ancestor.id)).to eq(false)
- end
-
- it 'returns false on nil-values' do
- expect(repository.ancestor?(nil, commit.id)).to eq(false)
- expect(repository.ancestor?(ancestor.id, nil)).to eq(false)
- expect(repository.ancestor?(nil, nil)).to eq(false)
- end
+ it 'it is an ancestor' do
+ expect(repository.ancestor?(ancestor.id, commit.id)).to eq(true)
+ end
- it 'returns false for invalid commit IDs' do
- expect(repository.ancestor?(commit.id, Gitlab::Git::BLANK_SHA)).to eq(false)
- expect(repository.ancestor?( Gitlab::Git::BLANK_SHA, commit.id)).to eq(false)
- end
+ it 'it is not an ancestor' do
+ expect(repository.ancestor?(commit.id, ancestor.id)).to eq(false)
end
- context 'with Gitaly enabled' do
- it_behaves_like('#ancestor?')
+ it 'returns false on nil-values' do
+ expect(repository.ancestor?(nil, commit.id)).to eq(false)
+ expect(repository.ancestor?(ancestor.id, nil)).to eq(false)
+ expect(repository.ancestor?(nil, nil)).to eq(false)
end
- context 'with Gitaly disabled', :skip_gitaly_mock do
- it_behaves_like('#ancestor?')
+ it 'returns false for invalid commit IDs' do
+ expect(repository.ancestor?(commit.id, Gitlab::Git::BLANK_SHA)).to eq(false)
+ expect(repository.ancestor?( Gitlab::Git::BLANK_SHA, commit.id)).to eq(false)
end
end
@@ -2403,4 +2301,22 @@ describe Repository do
repository.merge_base('master', 'fix')
end
end
+
+ describe '#cache' do
+ subject(:cache) { repository.send(:cache) }
+
+ it 'returns a RepositoryCache' do
+ expect(subject).to be_kind_of Gitlab::RepositoryCache
+ end
+
+ it 'when is_wiki it includes wiki as part of key' do
+ allow(repository).to receive(:is_wiki) { true }
+
+ expect(subject.namespace).to include('wiki')
+ end
+
+ it 'when is_wiki is false extra_namespace is nil' do
+ expect(subject.namespace).not_to include('wiki')
+ end
+ end
end
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index 2c01578aaca..82ff2a002e0 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -226,7 +226,7 @@ describe Todo do
create(:todo, target: create(:merge_request))
- expect(described_class.for_type(Issue)).to eq([todo])
+ expect(described_class.for_type(Issue.name)).to eq([todo])
end
end
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index b87a2d871e5..cba22b2cc4e 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -200,180 +200,160 @@ describe WikiPage do
end
describe '#create' do
- shared_examples 'create method' do
- context 'with valid attributes' do
- it 'raises an error if a page with the same path already exists' do
- create_page('New Page', 'content')
- create_page('foo/bar', 'content')
- expect { create_page('New Page', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
- expect { create_page('foo/bar', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
-
- destroy_page('New Page')
- destroy_page('bar', 'foo')
- end
+ context 'with valid attributes' do
+ it 'raises an error if a page with the same path already exists' do
+ create_page('New Page', 'content')
+ create_page('foo/bar', 'content')
+ expect { create_page('New Page', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
+ expect { create_page('foo/bar', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
- it 'if the title is preceded by a / it is removed' do
- create_page('/New Page', 'content')
+ destroy_page('New Page')
+ destroy_page('bar', 'foo')
+ end
- expect(wiki.find_page('New Page')).not_to be_nil
+ it 'if the title is preceded by a / it is removed' do
+ create_page('/New Page', 'content')
- destroy_page('New Page')
- end
+ expect(wiki.find_page('New Page')).not_to be_nil
+
+ destroy_page('New Page')
end
end
+ end
- context 'when Gitaly is enabled' do
- it_behaves_like 'create method'
+ describe "#update" do
+ before do
+ create_page("Update", "content")
+ @page = wiki.find_page("Update")
end
- context 'when Gitaly is disabled', :skip_gitaly_mock do
- it_behaves_like 'create method'
+ after do
+ destroy_page(@page.title, @page.directory)
end
- end
- describe "#update" do
- shared_examples 'update method' do
- before do
- create_page("Update", "content")
+ context "with valid attributes" do
+ it "updates the content of the page" do
+ new_content = "new content"
+
+ @page.update(content: new_content)
@page = wiki.find_page("Update")
- end
- after do
- destroy_page(@page.title, @page.directory)
+ expect(@page.content).to eq("new content")
end
- context "with valid attributes" do
- it "updates the content of the page" do
- new_content = "new content"
-
- @page.update(content: new_content)
- @page = wiki.find_page("Update")
-
- expect(@page.content).to eq("new content")
- end
+ it "updates the title of the page" do
+ new_title = "Index v.1.2.4"
- it "updates the title of the page" do
- new_title = "Index v.1.2.4"
+ @page.update(title: new_title)
+ @page = wiki.find_page(new_title)
- @page.update(title: new_title)
- @page = wiki.find_page(new_title)
-
- expect(@page.title).to eq(new_title)
- end
+ expect(@page.title).to eq(new_title)
+ end
- it "returns true" do
- expect(@page.update(content: "more content")).to be_truthy
- end
+ it "returns true" do
+ expect(@page.update(content: "more content")).to be_truthy
end
+ end
- context 'with same last commit sha' do
- it 'returns true' do
- expect(@page.update(content: 'more content', last_commit_sha: @page.last_commit_sha)).to be_truthy
- end
+ context 'with same last commit sha' do
+ it 'returns true' do
+ expect(@page.update(content: 'more content', last_commit_sha: @page.last_commit_sha)).to be_truthy
end
+ end
- context 'with different last commit sha' do
- it 'raises exception' do
- expect { @page.update(content: 'more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError)
- end
+ context 'with different last commit sha' do
+ it 'raises exception' do
+ expect { @page.update(content: 'more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError)
end
+ end
- context 'when renaming a page' do
- it 'raises an error if the page already exists' do
- create_page('Existing Page', 'content')
+ context 'when renaming a page' do
+ it 'raises an error if the page already exists' do
+ create_page('Existing Page', 'content')
- expect { @page.update(title: 'Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
- expect(@page.title).to eq 'Update'
- expect(@page.content).to eq 'new_content'
+ expect { @page.update(title: 'Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
+ expect(@page.title).to eq 'Update'
+ expect(@page.content).to eq 'new_content'
- destroy_page('Existing Page')
- end
+ destroy_page('Existing Page')
+ end
- it 'updates the content and rename the file' do
- new_title = 'Renamed Page'
- new_content = 'updated content'
+ it 'updates the content and rename the file' do
+ new_title = 'Renamed Page'
+ new_content = 'updated content'
- expect(@page.update(title: new_title, content: new_content)).to be_truthy
+ expect(@page.update(title: new_title, content: new_content)).to be_truthy
- @page = wiki.find_page(new_title)
+ @page = wiki.find_page(new_title)
- expect(@page).not_to be_nil
- expect(@page.content).to eq new_content
- end
+ expect(@page).not_to be_nil
+ expect(@page.content).to eq new_content
end
+ end
- context 'when moving a page' do
- it 'raises an error if the page already exists' do
- create_page('foo/Existing Page', 'content')
-
- expect { @page.update(title: 'foo/Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
- expect(@page.title).to eq 'Update'
- expect(@page.content).to eq 'new_content'
+ context 'when moving a page' do
+ it 'raises an error if the page already exists' do
+ create_page('foo/Existing Page', 'content')
- destroy_page('Existing Page', 'foo')
- end
+ expect { @page.update(title: 'foo/Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
+ expect(@page.title).to eq 'Update'
+ expect(@page.content).to eq 'new_content'
- it 'updates the content and moves the file' do
- new_title = 'foo/Other Page'
- new_content = 'new_content'
-
- expect(@page.update(title: new_title, content: new_content)).to be_truthy
+ destroy_page('Existing Page', 'foo')
+ end
- page = wiki.find_page(new_title)
+ it 'updates the content and moves the file' do
+ new_title = 'foo/Other Page'
+ new_content = 'new_content'
- expect(page).not_to be_nil
- expect(page.content).to eq new_content
- end
+ expect(@page.update(title: new_title, content: new_content)).to be_truthy
- context 'in subdir' do
- before do
- create_page('foo/Existing Page', 'content')
- @page = wiki.find_page('foo/Existing Page')
- end
+ page = wiki.find_page(new_title)
- it 'moves the page to the root folder if the title is preceded by /', :skip_gitaly_mock do
- expect(@page.slug).to eq 'foo/Existing-Page'
- expect(@page.update(title: '/Existing Page', content: 'new_content')).to be_truthy
- expect(@page.slug).to eq 'Existing-Page'
- end
+ expect(page).not_to be_nil
+ expect(page.content).to eq new_content
+ end
- it 'does nothing if it has the same title' do
- original_path = @page.slug
+ context 'in subdir' do
+ before do
+ create_page('foo/Existing Page', 'content')
+ @page = wiki.find_page('foo/Existing Page')
+ end
- expect(@page.update(title: 'Existing Page', content: 'new_content')).to be_truthy
- expect(@page.slug).to eq original_path
- end
+ it 'moves the page to the root folder if the title is preceded by /' do
+ expect(@page.slug).to eq 'foo/Existing-Page'
+ expect(@page.update(title: '/Existing Page', content: 'new_content')).to be_truthy
+ expect(@page.slug).to eq 'Existing-Page'
end
- context 'in root dir' do
- it 'does nothing if the title is preceded by /' do
- original_path = @page.slug
+ it 'does nothing if it has the same title' do
+ original_path = @page.slug
- expect(@page.update(title: '/Update', content: 'new_content')).to be_truthy
- expect(@page.slug).to eq original_path
- end
+ expect(@page.update(title: 'Existing Page', content: 'new_content')).to be_truthy
+ expect(@page.slug).to eq original_path
end
end
- context "with invalid attributes" do
- it 'aborts update if title blank' do
- expect(@page.update(title: '', content: 'new_content')).to be_falsey
- expect(@page.content).to eq 'new_content'
+ context 'in root dir' do
+ it 'does nothing if the title is preceded by /' do
+ original_path = @page.slug
- page = wiki.find_page('Update')
- expect(page.content).to eq 'content'
-
- @page.title = 'Update'
+ expect(@page.update(title: '/Update', content: 'new_content')).to be_truthy
+ expect(@page.slug).to eq original_path
end
end
end
- context 'when Gitaly is enabled' do
- it_behaves_like 'update method'
- end
+ context "with invalid attributes" do
+ it 'aborts update if title blank' do
+ expect(@page.update(title: '', content: 'new_content')).to be_falsey
+ expect(@page.content).to eq 'new_content'
- context 'when Gitaly is disabled', :skip_gitaly_mock do
- it_behaves_like 'update method'
+ page = wiki.find_page('Update')
+ expect(page.content).to eq 'content'
+
+ @page.title = 'Update'
+ end
end
end
@@ -394,34 +374,24 @@ describe WikiPage do
end
describe "#versions" do
- shared_examples 'wiki page versions' do
- let(:page) { wiki.find_page("Update") }
+ let(:page) { wiki.find_page("Update") }
- before do
- create_page("Update", "content")
- end
-
- after do
- destroy_page("Update")
- end
-
- it "returns an array of all commits for the page" do
- 3.times { |i| page.update(content: "content #{i}") }
-
- expect(page.versions.count).to eq(4)
- end
+ before do
+ create_page("Update", "content")
+ end
- it 'returns instances of WikiPageVersion' do
- expect(page.versions).to all( be_a(Gitlab::Git::WikiPageVersion) )
- end
+ after do
+ destroy_page("Update")
end
- context 'when Gitaly is enabled' do
- it_behaves_like 'wiki page versions'
+ it "returns an array of all commits for the page" do
+ 3.times { |i| page.update(content: "content #{i}") }
+
+ expect(page.versions.count).to eq(4)
end
- context 'when Gitaly is disabled', :disable_gitaly do
- it_behaves_like 'wiki page versions'
+ it 'returns instances of WikiPageVersion' do
+ expect(page.versions).to all( be_a(Gitlab::Git::WikiPageVersion) )
end
end
@@ -555,23 +525,13 @@ describe WikiPage do
end
describe '#formatted_content' do
- shared_examples 'fetching page formatted content' do
- it 'returns processed content of the page' do
- subject.create({ title: "RDoc", content: "*bold*", format: "rdoc" })
- page = wiki.find_page('RDoc')
-
- expect(page.formatted_content).to eq("\n<p><strong>bold</strong></p>\n")
+ it 'returns processed content of the page' do
+ subject.create({ title: "RDoc", content: "*bold*", format: "rdoc" })
+ page = wiki.find_page('RDoc')
- destroy_page('RDoc')
- end
- end
-
- context 'when Gitaly wiki_page_formatted_data is enabled' do
- it_behaves_like 'fetching page formatted content'
- end
+ expect(page.formatted_content).to eq("\n<p><strong>bold</strong></p>\n")
- context 'when Gitaly wiki_page_formatted_data is disabled', :disable_gitaly do
- it_behaves_like 'fetching page formatted content'
+ destroy_page('RDoc')
end
end
diff --git a/spec/services/merge_requests/create_from_issue_service_spec.rb b/spec/services/merge_requests/create_from_issue_service_spec.rb
index b1882df732d..393299cce00 100644
--- a/spec/services/merge_requests/create_from_issue_service_spec.rb
+++ b/spec/services/merge_requests/create_from_issue_service_spec.rb
@@ -61,7 +61,15 @@ describe MergeRequests::CreateFromIssueService do
expect(project.repository.branch_exists?(custom_source_branch)).to be_truthy
end
- it 'creates a system note' do
+ it 'creates the new_merge_request system note' do
+ expect(SystemNoteService).to receive(:new_merge_request).with(issue, project, user, instance_of(MergeRequest))
+
+ service.execute
+ end
+
+ it 'creates the new_issue_branch system note when the branch could be created but the merge_request cannot be created' do
+ project.project_feature.update!(merge_requests_access_level: ProjectFeature::DISABLED)
+
expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, issue.to_branch_name)
service.execute
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 5a7cafcb60f..938764f40b0 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1222,6 +1222,37 @@ describe QuickActions::InterpretService do
expect(commands).to be_empty
expect(text).to eq("#{described_class::SHRUG}\n/close")
end
+
+ context '/create_merge_request command' do
+ let(:branch_name) { '1-feature' }
+ let(:content) { "/create_merge_request #{branch_name}" }
+ let(:issuable) { issue }
+
+ context 'if issuable is not an Issue' do
+ let(:issuable) { merge_request }
+
+ it_behaves_like 'empty command'
+ end
+
+ context "when logged user cannot create_merge_requests in the project" do
+ let(:project) { create(:project, :archived) }
+
+ it_behaves_like 'empty command'
+ end
+
+ context 'when logged user cannot push code to the project' do
+ let(:project) { create(:project, :private) }
+ let(:service) { described_class.new(project, create(:user)) }
+
+ it_behaves_like 'empty command'
+ end
+
+ it 'populates create_merge_request with branch_name and issue iid' do
+ _, updates = service.execute(content, issuable)
+
+ expect(updates).to eq(create_merge_request: { branch_name: branch_name, issue_iid: issuable.iid })
+ end
+ end
end
describe '#explain' do
@@ -1473,5 +1504,27 @@ describe QuickActions::InterpretService do
end
end
end
+
+ describe 'create a merge request' do
+ context 'with no branch name' do
+ let(:content) { '/create_merge_request' }
+
+ it 'uses the default branch name' do
+ _, explanations = service.explain(content, issue)
+
+ expect(explanations).to eq(['Creates a branch and a merge request to resolve this issue'])
+ end
+ end
+
+ context 'with a branch name' do
+ let(:content) { '/create_merge_request foo' }
+
+ it 'uses the given branch name' do
+ _, explanations = service.explain(content, issue)
+
+ expect(explanations).to eq(["Creates branch 'foo' and a merge request to resolve this issue"])
+ end
+ end
+ end
end
end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index a18126ee339..0fbfcb34e50 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -432,6 +432,20 @@ describe SystemNoteService do
end
end
+ describe '.new_merge_request' do
+ subject { described_class.new_merge_request(noteable, project, author, merge_request) }
+
+ let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'merge' }
+ end
+
+ it 'sets the new merge request note text' do
+ expect(subject.note).to eq("created merge request #{merge_request.to_reference} to address this issue")
+ end
+ end
+
describe '.cross_reference' do
subject { described_class.cross_reference(noteable, mentioner, author) }
diff --git a/spec/support/gitaly.rb b/spec/support/gitaly.rb
deleted file mode 100644
index 614aaa73693..00000000000
--- a/spec/support/gitaly.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-RSpec.configure do |config|
- config.before(:each) do |example|
- if example.metadata[:disable_gitaly]
- # Use 'and_wrap_original' to make sure the arguments are valid
- allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_wrap_original { |m, *args| m.call(*args) && false }
- else
- next if example.metadata[:skip_gitaly_mock]
-
- # Use 'and_wrap_original' to make sure the arguments are valid
- allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_wrap_original do |m, *args|
- m.call(*args)
- !Gitlab::GitalyClient.explicit_opt_in_required.include?(args.first)
- end
- end
- end
-end
diff --git a/spec/support/helpers/devise_helpers.rb b/spec/support/helpers/devise_helpers.rb
index 66874e10f38..d32bc2424c0 100644
--- a/spec/support/helpers/devise_helpers.rb
+++ b/spec/support/helpers/devise_helpers.rb
@@ -8,8 +8,15 @@ module DeviseHelpers
end
def env_from_context(context)
+ # When we modify env_config, that is on the global
+ # Rails.application, and we need to stub it and allow it to be
+ # modified in-place, without polluting later tests.
if context.respond_to?(:env_config)
- context.env_config
+ context.env_config.deep_dup.tap do |env|
+ allow(context).to receive(:env_config).and_return(env)
+ end
+ # When we modify env, then the context is a request, or something
+ # else that only lives for a single spec.
elsif context.respond_to?(:env)
context.env
end