summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml3
-rw-r--r--.gitlab/ci/reports.gitlab-ci.yml8
-rw-r--r--.rubocop.yml14
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock10
-rw-r--r--PHILOSOPHY.md5
-rw-r--r--PROCESS.md4
-rw-r--r--README.md13
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue20
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/actions.vue6
-rw-r--r--app/assets/javascripts/main.js2
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue4
-rw-r--r--app/assets/javascripts/tracking.js28
-rw-r--r--app/assets/stylesheets/csslab.scss1
-rw-r--r--app/assets/stylesheets/framework/typography.scss2
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/pages/diff.scss28
-rw-r--r--app/assets/stylesheets/pages/search.scss10
-rw-r--r--app/assets/stylesheets/pages/todos.scss16
-rw-r--r--app/controllers/boards/lists_controller.rb24
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/finders/group_projects_finder.rb12
-rw-r--r--app/finders/members_finder.rb35
-rw-r--r--app/helpers/notes_helper.rb4
-rw-r--r--app/helpers/todos_helper.rb18
-rw-r--r--app/models/ci/job_artifact.rb2
-rw-r--r--app/models/clusters/applications/runner.rb2
-rw-r--r--app/models/commit.rb7
-rw-r--r--app/models/concerns/noteable.rb4
-rw-r--r--app/models/lfs_object.rb1
-rw-r--r--app/models/list.rb54
-rw-r--r--app/models/list_user_preference.rb10
-rw-r--r--app/models/project.rb1
-rw-r--r--app/models/todo.rb4
-rw-r--r--app/serializers/merge_request_noteable_entity.rb53
-rw-r--r--app/serializers/merge_request_poll_widget_entity.rb10
-rw-r--r--app/serializers/merge_request_serializer.rb2
-rw-r--r--app/serializers/merge_request_widget_entity.rb12
-rw-r--r--app/services/base_count_service.rb2
-rw-r--r--app/services/boards/lists/list_service.rb2
-rw-r--r--app/services/boards/lists/update_service.rb56
-rw-r--r--app/services/projects/lfs_pointers/lfs_link_service.rb29
-rw-r--r--app/services/system_note_service.rb10
-rw-r--r--app/views/admin/application_settings/_ip_limits.html.haml8
-rw-r--r--app/views/admin/application_settings/network.html.haml2
-rw-r--r--app/views/dashboard/todos/_todo.html.haml34
-rw-r--r--app/views/groups/edit.html.haml2
-rw-r--r--app/views/groups/settings/_permissions.html.haml2
-rw-r--r--app/views/layouts/_head.html.haml1
-rw-r--r--app/views/layouts/_snowplow.html.haml21
-rw-r--r--app/views/layouts/nav/sidebar/_admin.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml2
-rw-r--r--app/views/projects/blob/_blob.html.haml2
-rw-r--r--app/views/projects/blob/preview.html.haml2
-rw-r--r--app/views/projects/blob/viewers/_markup.html.haml2
-rw-r--r--app/views/projects/deployments/_deployment.html.haml3
-rw-r--r--app/views/projects/merge_requests/show.html.haml13
-rw-r--r--app/views/projects/snippets/show.html.haml2
-rw-r--r--app/views/projects/wikis/show.html.haml2
-rw-r--r--app/views/shared/boards/_show.html.haml2
-rw-r--r--app/views/shared/runners/_form.html.haml5
-rw-r--r--changelogs/unreleased/35060-remove-token-field.yml5
-rw-r--r--changelogs/unreleased/56130-operations-environments-shows-incorrect-deployment-date-for-manual-.yml6
-rw-r--r--changelogs/unreleased/57538-not-null-constraint-on-users-private-profile.yml5
-rw-r--r--changelogs/unreleased/60141-mr-resolve-conflicts-file-headers-bad-positioning-on-scroll.yml5
-rw-r--r--changelogs/unreleased/62284-follow-up-from-resolve-api-to-get-all-project-group-members-returns-duplicates.yml5
-rw-r--r--changelogs/unreleased/63262-notes-are-persisted-with-the-user-s-locale.yml5
-rw-r--r--changelogs/unreleased/bump-pages-1-8.yml5
-rw-r--r--changelogs/unreleased/cluster_deployments.yml5
-rw-r--r--changelogs/unreleased/fix-search-input-dropdown.yml5
-rw-r--r--changelogs/unreleased/id-optimize-sql-requests-mr-show.yml5
-rw-r--r--changelogs/unreleased/issue_40630.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-move-api.yml5
-rw-r--r--changelogs/unreleased/sh-lfs-object-batches.yml5
-rw-r--r--changelogs/unreleased/sh-upgrade-mermaid-8-2-4.yml5
-rw-r--r--changelogs/unreleased/ss-add-board-name-to-page-title.yml5
-rw-r--r--changelogs/unreleased/todos-include-issue-mr-titles.yml5
-rw-r--r--changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-8-0.yml5
-rw-r--r--config/application.rb1
-rw-r--r--config/initializers/peek.rb1
-rw-r--r--db/migrate/20190819131155_add_cluster_status_index_to_deployments.rb17
-rw-r--r--db/migrate/20190822181528_create_list_user_preferences.rb16
-rw-r--r--db/migrate/20190826090628_remove_redundant_deployments_index.rb18
-rw-r--r--db/migrate/20190828083843_add_index_to_ci_job_artifacts_on_project_id_for_security_reports.rb22
-rw-r--r--db/post_migrate/20190725080128_set_not_null_on_users_private_profile.rb26
-rw-r--r--db/schema.rb20
-rw-r--r--doc/README.md2
-rw-r--r--doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md4
-rw-r--r--doc/administration/auth/okta.md16
-rw-r--r--doc/administration/geo/disaster_recovery/index.md2
-rw-r--r--doc/administration/geo/replication/troubleshooting.md4
-rw-r--r--doc/administration/gitaly/index.md17
-rw-r--r--doc/administration/high_availability/gitlab.md27
-rw-r--r--doc/administration/integration/plantuml.md3
-rw-r--r--doc/administration/logs.md9
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md11
-rw-r--r--doc/administration/pages/source.md16
-rw-r--r--doc/administration/raketasks/github_import.md2
-rw-r--r--doc/administration/raketasks/ldap.md4
-rw-r--r--doc/administration/raketasks/maintenance.md4
-rw-r--r--doc/administration/raketasks/uploads/migrate.md2
-rw-r--r--doc/administration/troubleshooting/elasticsearch.md6
-rw-r--r--doc/administration/troubleshooting/sidekiq.md15
-rw-r--r--doc/api/README.md4
-rw-r--r--doc/api/graphql/reference/index.md1
-rw-r--r--doc/api/groups.md1
-rw-r--r--doc/api/project_snippets.md58
-rw-r--r--doc/ci/README.md2
-rw-r--r--doc/ci/directed_acyclic_graph/index.md2
-rw-r--r--doc/ci/examples/license_management.md4
-rw-r--r--doc/ci/jenkins/index.md8
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md2
-rw-r--r--doc/ci/runners/README.md3
-rw-r--r--doc/ci/services/mysql.md4
-rw-r--r--doc/ci/triggers/README.md5
-rw-r--r--doc/ci/yaml/README.md7
-rw-r--r--doc/development/contributing/index.md20
-rw-r--r--doc/development/contributing/issue_workflow.md305
-rw-r--r--doc/development/contributing/merge_request_workflow.md2
-rw-r--r--doc/development/documentation/styleguide.md14
-rw-r--r--doc/development/ee_features.md2
-rw-r--r--doc/development/fe_guide/performance.md2
-rw-r--r--doc/development/go_guide/index.md2
-rw-r--r--doc/development/i18n/translation.md1
-rw-r--r--doc/development/new_fe_guide/dependencies.md2
-rw-r--r--doc/development/new_fe_guide/development/testing.md1
-rw-r--r--doc/development/testing_guide/end_to_end/quick_start_guide.md2
-rw-r--r--doc/development/testing_guide/end_to_end/style_guide.md2
-rw-r--r--doc/development/testing_guide/index.md4
-rw-r--r--doc/development/testing_guide/review_apps.md2
-rw-r--r--doc/development/testing_guide/testing_levels.md2
-rw-r--r--doc/development/ux_guide/animation.md4
-rw-r--r--doc/development/ux_guide/illustrations.md4
-rw-r--r--doc/gitlab-basics/add-merge-request.md2
-rw-r--r--doc/gitlab-basics/create-project.md2
-rw-r--r--doc/gitlab-basics/create-your-ssh-keys.md2
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/security/rack_attack.md9
-rw-r--r--doc/topics/autodevops/index.md2
-rw-r--r--doc/user/admin_area/settings/terms.md3
-rw-r--r--doc/user/admin_area/settings/third_party_offers.md3
-rw-r--r--doc/user/application_security/license_compliance/img/license_compliance.png (renamed from doc/user/application_security/license_management/img/license_management.png)bin5184 -> 5184 bytes
-rw-r--r--doc/user/application_security/license_compliance/img/license_compliance_add_license.png (renamed from doc/user/application_security/license_management/img/license_management_add_license.png)bin24247 -> 24247 bytes
-rw-r--r--doc/user/application_security/license_compliance/img/license_compliance_decision.png (renamed from doc/user/application_security/license_management/img/license_management_decision.png)bin5975 -> 5975 bytes
-rw-r--r--doc/user/application_security/license_compliance/img/license_compliance_pipeline_tab.png (renamed from doc/user/application_security/license_management/img/license_management_pipeline_tab.png)bin12115 -> 12115 bytes
-rw-r--r--doc/user/application_security/license_compliance/img/license_compliance_search.png (renamed from doc/user/application_security/license_management/img/license_management_search.png)bin28237 -> 28237 bytes
-rw-r--r--doc/user/application_security/license_compliance/img/license_compliance_settings.png (renamed from doc/user/application_security/license_management/img/license_management_settings.png)bin44790 -> 44790 bytes
-rw-r--r--doc/user/application_security/license_compliance/index.md243
-rw-r--r--doc/user/application_security/license_management/index.md244
-rw-r--r--doc/user/application_security/security_dashboard/index.md3
-rw-r--r--doc/user/clusters/applications.md3
-rw-r--r--doc/user/gitlab_com/index.md11
-rw-r--r--doc/user/markdown.md3
-rw-r--r--doc/user/permissions.md38
-rw-r--r--doc/user/project/clusters/index.md2
-rw-r--r--doc/user/project/img/protected_branches_devs_can_push.pngbin11221 -> 0 bytes
-rw-r--r--doc/user/project/img/protected_branches_devs_can_push_v12_3.pngbin0 -> 11941 bytes
-rw-r--r--doc/user/project/img/protected_branches_list.pngbin6933 -> 0 bytes
-rw-r--r--doc/user/project/img/protected_branches_list_v12_3.pngbin0 -> 8774 bytes
-rw-r--r--doc/user/project/img/protected_branches_page.pngbin7199 -> 0 bytes
-rw-r--r--doc/user/project/img/protected_branches_page_v12_3.pngbin0 -> 9445 bytes
-rw-r--r--doc/user/project/img/protected_tags_list.pngbin7227 -> 0 bytes
-rw-r--r--doc/user/project/img/protected_tags_list_v12_3.pngbin0 -> 4395 bytes
-rw-r--r--doc/user/project/img/protected_tags_page.pngbin13813 -> 0 bytes
-rw-r--r--doc/user/project/img/protected_tags_page_v12_3.pngbin0 -> 10431 bytes
-rw-r--r--doc/user/project/img/protected_tags_permissions_dropdown.pngbin7770 -> 0 bytes
-rw-r--r--doc/user/project/img/protected_tags_permissions_dropdown_v12_3.pngbin0 -> 4517 bytes
-rw-r--r--doc/user/project/import/tfvc.md2
-rw-r--r--doc/user/project/index.md2
-rw-r--r--doc/user/project/integrations/mattermost.md9
-rw-r--r--doc/user/project/integrations/prometheus.md30
-rw-r--r--doc/user/project/merge_requests/index.md4
-rw-r--r--doc/user/project/merge_requests/license_management.md4
-rw-r--r--doc/user/project/operations/feature_flags.md31
-rw-r--r--doc/user/project/operations/tracing.md6
-rw-r--r--doc/user/project/protected_branches.md6
-rw-r--r--doc/user/project/protected_tags.md6
-rw-r--r--doc/user/project/repository/index.md2
-rw-r--r--doc/workflow/issue_weight.md5
-rw-r--r--lib/api/groups.rb1
-rw-r--r--lib/api/helpers.rb33
-rw-r--r--lib/api/helpers/groups_helpers.rb7
-rw-r--r--lib/gitlab.rb2
-rw-r--r--lib/gitlab/danger/teammate.rb4
-rw-r--r--lib/gitlab/gitaly_client.rb2
-rw-r--r--lib/gitlab/performance_bar/with_top_level_warnings.rb19
-rw-r--r--lib/gitlab/snowplow_tracker.rb35
-rw-r--r--lib/gitlab/tracking.rb44
-rw-r--r--lib/gitlab/workhorse.rb6
-rw-r--r--lib/peek/views/active_record.rb18
-rw-r--r--lib/peek/views/detailed_view.rb45
-rw-r--r--lib/peek/views/gitaly.rb18
-rw-r--r--lib/peek/views/rugged.rb2
-rw-r--r--locale/gitlab.pot6
-rw-r--r--package.json3
-rw-r--r--qa/README.md11
-rw-r--r--qa/qa.rb7
-rw-r--r--qa/qa/page/admin/menu.rb8
-rw-r--r--qa/qa/page/admin/settings/component/ip_limits.rb30
-rw-r--r--qa/qa/page/admin/settings/network.rb23
-rw-r--r--qa/qa/page/group/settings/general.rb18
-rw-r--r--qa/qa/page/project/settings/auto_devops.rb21
-rw-r--r--qa/qa/page/project/settings/ci_cd.rb10
-rw-r--r--qa/qa/page/project/sub_menus/issues.rb9
-rw-r--r--qa/qa/page/project/web_ide/edit.rb6
-rw-r--r--qa/qa/resource/sandbox.rb2
-rw-r--r--qa/qa/runtime/api/client.rb21
-rw-r--r--qa/qa/specs/features/api/1_manage/rate_limits_spec.rb20
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb16
-rw-r--r--rubocop/cop/rspec/be_success_matcher.rb53
-rw-r--r--rubocop/rubocop.rb1
-rw-r--r--spec/controllers/boards/lists_controller_spec.rb44
-rw-r--r--spec/features/admin/admin_runners_spec.rb4
-rw-r--r--spec/features/dashboard/todos/todos_filtering_spec.rb12
-rw-r--r--spec/features/dashboard/todos/todos_sorting_spec.rb36
-rw-r--r--spec/features/dashboard/todos/todos_spec.rb18
-rw-r--r--spec/features/projects/files/user_browses_files_spec.rb1
-rw-r--r--spec/finders/members_finder_spec.rb44
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_noteable.json28
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_poll_widget.json8
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_widget.json3
-rw-r--r--spec/frontend/tracking_spec.js46
-rw-r--r--spec/frontend/vue_shared/components/file_icon_spec.js75
-rw-r--r--spec/javascripts/environments/environment_item_spec.js5
-rw-r--r--spec/javascripts/notes/mock_data.js2
-rw-r--r--spec/javascripts/vue_shared/components/file_icon_spec.js92
-rw-r--r--spec/lib/gitlab/danger/teammate_spec.rb8
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb17
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/performance_bar/with_top_level_warnings_spec.rb29
-rw-r--r--spec/lib/gitlab/snowplow_tracker_spec.rb45
-rw-r--r--spec/lib/gitlab/tracking_spec.rb88
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb13
-rw-r--r--spec/lib/gitlab_spec.rb27
-rw-r--r--spec/lib/peek/views/detailed_view_spec.rb81
-rw-r--r--spec/lib/peek/views/redis_detailed_spec.rb8
-rw-r--r--spec/models/commit_spec.rb18
-rw-r--r--spec/models/concerns/noteable_spec.rb18
-rw-r--r--spec/models/list_spec.rb79
-rw-r--r--spec/models/list_user_preference_spec.rb22
-rw-r--r--spec/models/todo_spec.rb4
-rw-r--r--spec/models/user_spec.rb2
-rw-r--r--spec/requests/api/project_snapshots_spec.rb7
-rw-r--r--spec/rubocop/cop/rspec/be_success_matcher_spec.rb63
-rw-r--r--spec/serializers/merge_request_serializer_spec.rb8
-rw-r--r--spec/services/boards/lists/list_service_spec.rb6
-rw-r--r--spec/services/boards/lists/update_service_spec.rb89
-rw-r--r--spec/services/projects/forks_count_service_spec.rb14
-rw-r--r--spec/services/projects/lfs_pointers/lfs_link_service_spec.rb18
-rw-r--r--spec/services/projects/open_issues_count_service_spec.rb13
-rw-r--r--spec/services/projects/open_merge_requests_count_service_spec.rb11
-rw-r--r--spec/services/system_note_service_spec.rb7
-rw-r--r--spec/services/users/keys_count_service_spec.rb44
-rw-r--r--spec/support/helpers/query_recorder.rb5
-rw-r--r--spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb3
-rw-r--r--spec/support/shared_examples/services/count_service_shared_examples.rb54
-rw-r--r--vendor/licenses.csv1
-rw-r--r--yarn.lock74
261 files changed, 2752 insertions, 1191 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4c7a8c05b37..27992024265 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,8 +18,11 @@ variables:
GIT_SUBMODULE_STRATEGY: "none"
GET_SOURCES_ATTEMPTS: "3"
KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
+ EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master-ee.json
FLAKY_RSPEC_SUITE_REPORT_PATH: rspec_flaky/report-suite.json
BUILD_ASSETS_IMAGE: "false"
+ ES_JAVA_OPTS: "-Xms256m -Xmx256m"
+ ELASTIC_URL: "http://elastic:changeme@docker.elastic.co-elasticsearch-elasticsearch:9200"
after_script:
- date
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml
index 2197f916484..efe33049939 100644
--- a/.gitlab/ci/reports.gitlab-ci.yml
+++ b/.gitlab/ci/reports.gitlab-ci.yml
@@ -17,6 +17,10 @@ sast:
variables:
SAST_BRAKEMAN_LEVEL: 2
SAST_EXCLUDED_PATHS: qa,spec,doc
+ artifacts:
+ expire_in: 7 days
+ paths:
+ - gl-sast-report.json
dependency_scanning:
extends: .reports
@@ -27,3 +31,7 @@ dast:
dependencies: ["review-deploy"]
before_script:
- export DAST_WEBSITE="$(cat review_app_url.txt)"
+ artifacts:
+ expire_in: 7 days
+ paths:
+ - gl-dast-report.json
diff --git a/.rubocop.yml b/.rubocop.yml
index 012f4890c33..a20924c21b7 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -50,7 +50,9 @@ Style/FrozenStringLiteralComment:
- 'config/**/*'
- 'danger/**/*'
- 'db/**/*'
- - 'ee/**/*'
+ - 'ee/db/**/*'
+ - 'ee/spec/**/*'
+ - 'ee/lib/tasks/**/*'
- 'lib/tasks/**/*'
- 'qa/**/*'
- 'rubocop/**/*'
@@ -91,6 +93,7 @@ Naming/FileName:
- JSON
- LDAP
- SAML
+ - SSO
- IO
- HMAC
- QA
@@ -265,3 +268,12 @@ RSpec/EnvAssignment:
- 'ee/spec/**/rails_helper.rb'
- 'spec/**/spec_helper.rb'
- 'ee/spec/**/spec_helper.rb'
+RSpec/BeSuccessMatcher:
+ Enabled: true
+ Include:
+ - 'spec/controllers/**/*'
+ - 'ee/spec/controllers/**/*'
+ - 'spec/support/shared_examples/controllers/**/*'
+ - 'ee/spec/support/shared_examples/controllers/**/*'
+ - 'spec/support/controllers/**/*'
+ - 'ee/spec/support/controllers/**/*'
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 943f9cbc4ec..27f9cd322bb 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.7.1
+1.8.0
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 3b6825376ad..e5c15102d9b 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-8.8.0
+8.9.0
diff --git a/Gemfile b/Gemfile
index 595dedd4656..6c7ef7264c3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -367,7 +367,6 @@ group :development, :test do
gem 'haml_lint', '~> 0.31.0', require: false
gem 'simplecov', '~> 0.16.1', require: false
gem 'bundler-audit', '~> 0.5.0', require: false
- gem 'mdl', '~> 0.5.0', require: false
gem 'benchmark-ips', '~> 2.3.0', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index ae0d0e78c37..dac68eac5b0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -475,7 +475,6 @@ GEM
kgio (2.11.2)
knapsack (1.17.0)
rake
- kramdown (1.17.0)
kubeclient (4.2.2)
http (~> 3.0)
recursive-open-struct (~> 1.0, >= 1.0.4)
@@ -511,10 +510,6 @@ GEM
mail_room (0.9.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
- mdl (0.5.0)
- kramdown (~> 1.12, >= 1.12.0)
- mixlib-cli (~> 1.7, >= 1.7.0)
- mixlib-config (~> 2.2, >= 2.2.1)
memoist (0.16.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
@@ -528,9 +523,6 @@ GEM
mini_mime (1.0.1)
mini_portile2 (2.4.0)
minitest (5.11.3)
- mixlib-cli (1.7.0)
- mixlib-config (2.2.18)
- tomlrb
msgpack (1.3.0)
multi_json (1.13.1)
multi_xml (0.6.0)
@@ -951,7 +943,6 @@ GEM
parslet (~> 1.8.0)
toml-rb (1.0.0)
citrus (~> 3.0, > 3.0)
- tomlrb (1.2.8)
truncato (0.7.11)
htmlentities (~> 4.3.1)
nokogiri (>= 1.7.0, <= 2.0)
@@ -1146,7 +1137,6 @@ DEPENDENCIES
lograge (~> 0.5)
loofah (~> 2.2)
mail_room (~> 0.9.1)
- mdl (~> 0.5.0)
memory_profiler (~> 0.9)
method_source (~> 0.8)
mimemagic (~> 0.3.2)
diff --git a/PHILOSOPHY.md b/PHILOSOPHY.md
index e966d88ef78..483063731d1 100644
--- a/PHILOSOPHY.md
+++ b/PHILOSOPHY.md
@@ -1 +1,4 @@
-This document is intended to communicate the product philosophy GitLab uses in creating GitLab Community Edition. The principles can be found in the [Product Section of the GitLab Handbook](https://about.gitlab.com/handbook/product/#product-at-gitlab). \ No newline at end of file
+To learn about the product philosophy GitLab the company uses in creating GitLab
+the product, visit our [Product Handbook page].
+
+[Product Handbook page]: https://about.gitlab.com/handbook/product/#product-at-gitlab
diff --git a/PROCESS.md b/PROCESS.md
index 22b68b0aaca..f0a82838f62 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -267,9 +267,7 @@ The two scenarios below can [bypass the exception request in the release process
When a bug is found:
1. Create an issue describing the problem in the most detailed way possible.
1. If possible, provide links to real examples and how to reproduce the problem.
-1. Label the issue properly, using the [team label](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#team-labels),
- the [subject label](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#subject-labels)
- and any other label that may apply in the specific case
+1. Label the issue properly, by respecting the [Partial triage level](https://about.gitlab.com/handbook/engineering/issue-triage/#partial-triage).
1. Notify the respective Engineering Manager to evaluate and apply the [Severity label](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#severity-labels) and [Priority label](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#priority-labels).
The counterpart Product Manager is included to weigh-in on prioritization as needed.
1. If the ~bug is **NOT** a regression:
diff --git a/README.md b/README.md
index 054e2d02461..bfc55f28279 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,15 @@
# GitLab
-## Test coverage
-
-- [![Ruby coverage](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby) Ruby
-- [![JavaScript coverage](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=karma)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-javascript) JavaScript
-
## Canonical source
The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/).
+The source of GitLab Enterprise Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ee).
+
+## Free trial
+
+You can request a free trial of GitLab Ultimate [on our website](https://about.gitlab.com/free-trial/).
+
## Open source software to collaborate on code
To see how GitLab looks please see the [features page on our website](https://about.gitlab.com/features/).
@@ -103,7 +104,7 @@ For upgrading information please see our [update page](https://about.gitlab.com/
## Documentation
-All documentation can be found on [docs.gitlab.com/ce/](https://docs.gitlab.com/ce/).
+All documentation can be found on <https://docs.gitlab.com>.
## Getting help
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index 95e1e8af9b3..1d4a6e64f9d 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -111,12 +111,7 @@ export default {
* @returns {Boolean|Undefined}
*/
canShowDate() {
- return (
- this.model &&
- this.model.last_deployment &&
- this.model.last_deployment.deployable &&
- this.model.last_deployment.deployable !== undefined
- );
+ return this.model && this.model.last_deployment && this.model.last_deployment.deployed_at;
},
/**
@@ -124,14 +119,9 @@ export default {
*
* @returns {String}
*/
- createdDate() {
- if (
- this.model &&
- this.model.last_deployment &&
- this.model.last_deployment.deployable &&
- this.model.last_deployment.deployable.created_at
- ) {
- return timeagoInstance.format(this.model.last_deployment.deployable.created_at);
+ deployedDate() {
+ if (this.canShowDate) {
+ return timeagoInstance.format(this.model.last_deployment.deployed_at);
}
return '';
},
@@ -547,7 +537,7 @@ export default {
<div v-if="!model.isFolder" class="table-section section-10" role="gridcell">
<div role="rowheader" class="table-mobile-header">{{ s__('Environments|Updated') }}</div>
<span v-if="canShowDate" class="environment-created-date-timeago table-mobile-content">
- {{ createdDate }}
+ {{ deployedDate }}
</span>
</div>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
index 8b356ee6e97..549324831e9 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
@@ -69,7 +69,11 @@ export default {
:disabled="currentBranch && !currentBranch.can_push"
:title="$options.currentBranchPermissionsTooltip"
>
- <span class="ide-radio-label" v-html="commitToCurrentBranchText"> </span>
+ <span
+ class="ide-radio-label"
+ data-qa-selector="commit_to_current_branch_radio"
+ v-html="commitToCurrentBranchText"
+ ></span>
</radio-group>
<radio-group
:value="$options.commitToNewBranch"
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 39f2097c174..0ddf40b0405 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -35,6 +35,7 @@ import initPerformanceBar from './performance_bar';
import initSearchAutocomplete from './search_autocomplete';
import GlFieldErrors from './gl_field_errors';
import initUserPopovers from './user_popovers';
+import { initUserTracking } from './tracking';
import { __ } from './locale';
import 'ee_else_ce/main_ee';
@@ -94,6 +95,7 @@ function deferredInitialisation() {
initLogoAnimation();
initUsagePingConsent();
initUserPopovers();
+ initUserTracking();
if (document.querySelector('.search')) initSearchAutocomplete();
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index a0695f9e191..16a0fb3f33a 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -75,9 +75,9 @@ export default {
},
allDiscussions() {
if (this.isLoading) {
- const totalNotes = parseInt(this.notesData.totalNotes, 10) || 0;
+ const prerenderedNotesCount = parseInt(this.notesData.prerenderedNotesCount, 10) || 0;
- return new Array(totalNotes).fill({
+ return new Array(prerenderedNotesCount).fill({
isSkeletonNote: true,
});
}
diff --git a/app/assets/javascripts/tracking.js b/app/assets/javascripts/tracking.js
index a852f937eec..03281b5ef49 100644
--- a/app/assets/javascripts/tracking.js
+++ b/app/assets/javascripts/tracking.js
@@ -1,5 +1,23 @@
import $ from 'jquery';
+const DEFAULT_SNOWPLOW_OPTIONS = {
+ namespace: 'gl',
+ hostname: window.location.hostname,
+ cookieDomain: window.location.hostname,
+ appId: '',
+ userFingerprint: false,
+ respectDoNotTrack: true,
+ forceSecureTracker: true,
+ eventMethod: 'post',
+ contexts: { webPage: true },
+ // Page tracking tracks a single event when the page loads.
+ pageTrackingEnabled: false,
+ // Activity tracking tracks when a user is still interacting with the page.
+ // Events like scrolling and mouse movements are used to determine if the
+ // user has the tab active and is still actively engaging.
+ activityTrackingEnabled: false,
+};
+
const extractData = (el, opts = {}) => {
const { trackEvent, trackLabel = '', trackProperty = '' } = el.dataset;
let trackValue = el.dataset.trackValue || el.value || '';
@@ -71,3 +89,13 @@ export default class Tracking {
};
}
}
+
+export function initUserTracking() {
+ if (!Tracking.enabled()) return;
+
+ const opts = Object.assign({}, DEFAULT_SNOWPLOW_OPTIONS, window.snowplowOptions);
+ window.snowplow('newTracker', opts.namespace, opts.hostname, opts);
+
+ if (opts.activityTrackingEnabled) window.snowplow('enableActivityTracking', 30, 30);
+ if (opts.pageTrackingEnabled) window.snowplow('trackPageView'); // must be after enableActivityTracking
+}
diff --git a/app/assets/stylesheets/csslab.scss b/app/assets/stylesheets/csslab.scss
deleted file mode 100644
index 87c59cd42c0..00000000000
--- a/app/assets/stylesheets/csslab.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import "@gitlab/csslab/dist/css/csslab-slim";
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index c201605e83d..afcc7f8a1db 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -2,7 +2,7 @@
* Apply Markup (Markdown/AsciiDoc) typography
*
*/
-.md:not(.use-csslab) {
+.md {
color: $gl-text-color;
word-wrap: break-word;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 9871771542d..7a3fd2adfbb 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -529,7 +529,7 @@ $award-emoji-width-xs: 90%;
*/
$search-input-border-color: rgba($blue-400, 0.8);
$search-input-width: 200px;
-$search-input-active-width: 320px;
+$search-input-xl-width: 320px;
$location-icon-color: #e7e9ed;
/*
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 77a2fd6b876..defa1a6c0d5 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -2,8 +2,14 @@
.diff-file {
margin-bottom: $gl-padding;
+ &.conflict {
+ border-top: 1px solid $border-color;
+ }
+
.file-title,
.file-title-flex-parent {
+ border-top-left-radius: $border-radius-default;
+ border-top-right-radius: $border-radius-default;
cursor: pointer;
@media (min-width: map-get($grid-breakpoints, md)) {
@@ -67,6 +73,28 @@
}
}
+ @media (min-width: map-get($grid-breakpoints, md)) {
+ &.conflict .file-title,
+ &.conflict .file-title-flex-parent {
+ top: $header-height;
+ }
+
+ .with-performance-bar &.conflict .file-title,
+ .with-performance-bar &.conflict .file-title-flex-parent {
+ top: $header-height + $performance-bar-height;
+ }
+
+ .with-system-header &.conflict .file-title,
+ .with-system-header &.conflict .file-title-flex-parent {
+ top: $header-height + $system-header-height;
+ }
+
+ .with-system-header.with-performance-bar &.conflict .file-title,
+ .with-system-header.with-performance-bar &.conflict .file-title-flex-parent {
+ top: $header-height + $performance-bar-height + $system-header-height;
+ }
+ }
+
.diff-content {
background: $white-light;
color: $gl-text-color;
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 58e46cfb70f..74380ec995a 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -48,6 +48,10 @@ input[type='checkbox']:hover {
background-color ease-in-out $default-transition-duration,
width ease-in-out $default-transition-duration;
+ @include media-breakpoint-up(xl) {
+ width: $search-input-xl-width;
+ }
+
&:hover {
box-shadow: none;
}
@@ -116,7 +120,7 @@ input[type='checkbox']:hover {
overflow: auto;
@include media-breakpoint-up(xl) {
- width: $search-input-active-width;
+ width: $search-input-xl-width;
}
}
@@ -131,10 +135,6 @@ input[type='checkbox']:hover {
border-color: $blue-300;
box-shadow: none;
- @include media-breakpoint-up(xl) {
- width: $search-input-active-width;
- }
-
.search-input-wrap {
.search-icon,
.clear-icon {
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index 7b64c67ae34..ece0ac04baf 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -72,12 +72,7 @@
@include transition(opacity);
.todo-title {
- display: flex;
-
> .title-item {
- flex: 0 0 auto;
- margin: 0 2px;
-
&:first-child {
margin-left: 0;
}
@@ -105,8 +100,12 @@
font-size: 14px;
}
- .action-name {
- font-weight: $gl-font-weight-normal;
+ .todo-label,
+ .todo-project {
+ a {
+ color: $blue-600;
+ font-weight: $gl-font-weight-normal;
+ }
}
.todo-body {
@@ -170,7 +169,7 @@
}
}
-@include media-breakpoint-down(xs) {
+@include media-breakpoint-down(sm) {
.todo {
.avatar {
display: none;
@@ -179,7 +178,6 @@
.todo-item {
.todo-title {
- flex-flow: row wrap;
margin-bottom: 10px;
.todo-label {
diff --git a/app/controllers/boards/lists_controller.rb b/app/controllers/boards/lists_controller.rb
index ccd02144671..08b4748d7e1 100644
--- a/app/controllers/boards/lists_controller.rb
+++ b/app/controllers/boards/lists_controller.rb
@@ -4,7 +4,7 @@ module Boards
class ListsController < Boards::ApplicationController
include BoardsResponses
- before_action :authorize_admin_list, only: [:create, :update, :destroy, :generate]
+ before_action :authorize_admin_list, only: [:create, :destroy, :generate]
before_action :authorize_read_list, only: [:index]
skip_before_action :authenticate_user!, only: [:index]
@@ -15,7 +15,7 @@ module Boards
end
def create
- list = Boards::Lists::CreateService.new(board.parent, current_user, list_params).execute(board)
+ list = Boards::Lists::CreateService.new(board.parent, current_user, create_list_params).execute(board)
if list.valid?
render json: serialize_as_json(list)
@@ -26,12 +26,13 @@ module Boards
def update
list = board.lists.movable.find(params[:id])
- service = Boards::Lists::MoveService.new(board_parent, current_user, move_params)
+ service = Boards::Lists::UpdateService.new(board_parent, current_user, update_list_params)
+ result = service.execute(list)
- if service.execute(list)
+ if result[:status] == :success
head :ok
else
- head :unprocessable_entity
+ head result[:http_status]
end
end
@@ -50,7 +51,8 @@ module Boards
service = Boards::Lists::GenerateService.new(board_parent, current_user)
if service.execute(board)
- render json: serialize_as_json(board.lists.movable)
+ lists = board.lists.movable.preload_associations(current_user)
+ render json: serialize_as_json(lists)
else
head :unprocessable_entity
end
@@ -62,12 +64,12 @@ module Boards
%i[label_id]
end
- def list_params
+ def create_list_params
params.require(:list).permit(list_creation_attrs)
end
- def move_params
- params.require(:list).permit(:position)
+ def update_list_params
+ params.require(:list).permit(:collapsed, :position)
end
def serialize_as_json(resource)
@@ -78,7 +80,9 @@ module Boards
{
only: [:id, :list_type, :position],
methods: [:title],
- label: true
+ label: true,
+ collapsed: true,
+ current_user: current_user
}
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index f4cc0a5851b..d492c5227cf 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -46,6 +46,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
@noteable = @merge_request
@commits_count = @merge_request.commits_count
@issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar')
+ @current_user_data = UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestUserEntity).to_json
set_pipeline_variables
diff --git a/app/finders/group_projects_finder.rb b/app/finders/group_projects_finder.rb
index 4155b6af8da..5e0dbbfca2e 100644
--- a/app/finders/group_projects_finder.rb
+++ b/app/finders/group_projects_finder.rb
@@ -23,8 +23,12 @@ class GroupProjectsFinder < ProjectsFinder
attr_reader :group, :options
def initialize(group:, params: {}, options: {}, current_user: nil, project_ids_relation: nil)
- super(params: params, current_user: current_user, project_ids_relation: project_ids_relation)
- @group = group
+ super(
+ params: params,
+ current_user: current_user,
+ project_ids_relation: project_ids_relation
+ )
+ @group = group
@options = options
end
@@ -84,15 +88,13 @@ class GroupProjectsFinder < ProjectsFinder
options.fetch(:include_subgroups, false)
end
- # rubocop: disable CodeReuse/ActiveRecord
def owned_projects
if include_subgroups?
- Project.where(namespace_id: group.self_and_descendants.select(:id))
+ Project.for_group_and_its_subgroups(group)
else
group.projects
end
end
- # rubocop: enable CodeReuse/ActiveRecord
def shared_projects
group.shared_projects
diff --git a/app/finders/members_finder.rb b/app/finders/members_finder.rb
index f730b015c0a..e8c7f9622a9 100644
--- a/app/finders/members_finder.rb
+++ b/app/finders/members_finder.rb
@@ -60,15 +60,32 @@ class MembersFinder
# We're interested in a list of members without duplicates by user_id.
# We prefer project members over group members, project members should go first.
<<~SQL
- SELECT DISTINCT ON (user_id, invite_email) member_union.*
- FROM (#{union.to_sql}) AS member_union
- ORDER BY user_id,
- invite_email,
- CASE
- WHEN type = 'ProjectMember' THEN 1
- WHEN type = 'GroupMember' THEN 2
- ELSE 3
- END
+ SELECT DISTINCT ON (user_id, invite_email) #{member_columns}
+ FROM (#{union.to_sql}) AS #{member_union_table}
+ LEFT JOIN users on users.id = member_union.user_id
+ LEFT JOIN project_authorizations on project_authorizations.user_id = users.id
+ AND
+ project_authorizations.project_id = #{project.id}
+ ORDER BY user_id,
+ invite_email,
+ CASE
+ WHEN type = 'ProjectMember' THEN 1
+ WHEN type = 'GroupMember' THEN 2
+ ELSE 3
+ END
SQL
end
+
+ def member_union_table
+ 'member_union'
+ end
+
+ def member_columns
+ Member.column_names.map do |column_name|
+ # fallback to members.access_level when project_authorizations.access_level is missing
+ next "COALESCE(#{ProjectAuthorization.table_name}.access_level, #{member_union_table}.access_level) access_level" if column_name == 'access_level'
+
+ "#{member_union_table}.#{column_name}"
+ end.join(',')
+ end
end
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 2e31a5e2ed4..4e88b379e16 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module NotesHelper
+ MAX_PRERENDERED_NOTES = 10
+
def note_target_fields(note)
if note.noteable
hidden_field_tag(:target_type, note.noteable.class.name.underscore) +
@@ -169,7 +171,7 @@ module NotesHelper
closePath: close_issuable_path(issuable),
reopenPath: reopen_issuable_path(issuable),
notesPath: notes_url,
- totalNotes: issuable.discussions.length,
+ prerenderedNotesCount: issuable.capped_notes_count(MAX_PRERENDERED_NOTES),
lastFetchedAt: Time.now.to_i
}
end
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 38142bc68cb..f5333bb332e 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -33,7 +33,23 @@ module TodosHelper
todo.target_reference
end
- link_to text, todo_target_path(todo), class: 'has-tooltip', title: todo.target.title
+ link_to text, todo_target_path(todo)
+ end
+
+ def todo_target_title(todo)
+ if todo.target
+ "\"#{todo.target.title}\""
+ else
+ ""
+ end
+ end
+
+ def todo_parent_path(todo)
+ if todo.parent.is_a?(Group)
+ link_to todo.parent.name, group_path(todo.parent)
+ else
+ link_to_project(todo.project)
+ end
end
def todo_target_type_name(todo)
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index e132cb045e2..b4497d8af09 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -87,6 +87,8 @@ module Ci
scope :expired, -> (limit) { where('expire_at < ?', Time.now).limit(limit) }
+ scope :scoped_project, -> { where('ci_job_artifacts.project_id = projects.id') }
+
delegate :filename, :exists?, :open, to: :file
enum file_type: {
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index 6533b7a186e..329250255fd 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -3,7 +3,7 @@
module Clusters
module Applications
class Runner < ApplicationRecord
- VERSION = '0.7.0'.freeze
+ VERSION = '0.8.0'.freeze
self.table_name = 'clusters_applications_runners'
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 0889ce7e287..1470b50f396 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -35,6 +35,7 @@ class Commit
MIN_SHA_LENGTH = Gitlab::Git::Commit::MIN_SHA_LENGTH
COMMIT_SHA_PATTERN = /\h{#{MIN_SHA_LENGTH},40}/.freeze
+ EXACT_COMMIT_SHA_PATTERN = /\A#{COMMIT_SHA_PATTERN}\z/.freeze
# Used by GFM to match and present link extensions on node texts and hrefs.
LINK_EXTENSION_PATTERN = /(patch)/.freeze
@@ -90,7 +91,7 @@ class Commit
end
def valid_hash?(key)
- !!(/\A#{COMMIT_SHA_PATTERN}\z/ =~ key)
+ !!(EXACT_COMMIT_SHA_PATTERN =~ key)
end
def lazy(project, oid)
@@ -139,6 +140,10 @@ class Commit
'@'
end
+ def self.reference_valid?(reference)
+ !!(reference =~ EXACT_COMMIT_SHA_PATTERN)
+ end
+
# Pattern used to extract commit references from text
#
# This pattern supports cross-project references.
diff --git a/app/models/concerns/noteable.rb b/app/models/concerns/noteable.rb
index 4b428b0af83..6a44bc7c401 100644
--- a/app/models/concerns/noteable.rb
+++ b/app/models/concerns/noteable.rb
@@ -73,6 +73,10 @@ module Noteable
.discussions(self)
end
+ def capped_notes_count(max)
+ notes.limit(max).count
+ end
+
def grouped_diff_discussions(*args)
# Doesn't use `discussion_notes`, because this may include commit diff notes
# besides MR diff notes, that we do not want to display on the MR Changes tab.
diff --git a/app/models/lfs_object.rb b/app/models/lfs_object.rb
index 79a376ff0fd..40695a97d97 100644
--- a/app/models/lfs_object.rb
+++ b/app/models/lfs_object.rb
@@ -2,6 +2,7 @@
class LfsObject < ApplicationRecord
include AfterCommitQueue
+ include EachBatch
include ObjectStorage::BackgroundMove
has_many :lfs_objects_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
diff --git a/app/models/list.rb b/app/models/list.rb
index ccadd39bda2..ae7085f05a7 100644
--- a/app/models/list.rb
+++ b/app/models/list.rb
@@ -1,9 +1,11 @@
# frozen_string_literal: true
class List < ApplicationRecord
+ include Importable
+
belongs_to :board
belongs_to :label
- include Importable
+ has_many :list_user_preferences
enum list_type: { backlog: 0, label: 1, closed: 2, assignee: 3, milestone: 4 }
@@ -16,9 +18,24 @@ class List < ApplicationRecord
scope :destroyable, -> { where(list_type: list_types.slice(*destroyable_types).values) }
scope :movable, -> { where(list_type: list_types.slice(*movable_types).values) }
- scope :preload_associations, -> { preload(:board, :label) }
+
+ scope :preload_associations, -> (user) do
+ preload(:board, label: :priorities)
+ .with_preferences_for(user)
+ end
+
scope :ordered, -> { order(:list_type, :position) }
+ # Loads list with preferences for given user
+ # if preferences exists for user or not
+ scope :with_preferences_for, -> (user) do
+ return unless user
+
+ includes(:list_user_preferences).where(list_user_preferences: { user_id: [user.id, nil] })
+ end
+
+ alias_method :preferences, :list_user_preferences
+
class << self
def destroyable_types
[:label]
@@ -29,6 +46,31 @@ class List < ApplicationRecord
end
end
+ def preferences_for(user)
+ return preferences.build unless user
+
+ if preferences.loaded?
+ preloaded_preferences_for(user)
+ else
+ preferences.find_or_initialize_by(user: user)
+ end
+ end
+
+ def preloaded_preferences_for(user)
+ user_preferences =
+ preferences.find do |preference|
+ preference.user_id == user.id
+ end
+
+ user_preferences || preferences.build(user: user)
+ end
+
+ def update_preferences_for(user, preferences = {})
+ return unless user
+
+ preferences_for(user).update(preferences)
+ end
+
def destroyable?
self.class.destroyable_types.include?(list_type&.to_sym)
end
@@ -43,6 +85,14 @@ class List < ApplicationRecord
def as_json(options = {})
super(options).tap do |json|
+ json[:collapsed] = false
+
+ if options.key?(:collapsed)
+ preferences = preferences_for(options[:current_user])
+
+ json[:collapsed] = preferences.collapsed?
+ end
+
if options.key?(:label)
json[:label] = label.as_json(
project: board.project,
diff --git a/app/models/list_user_preference.rb b/app/models/list_user_preference.rb
new file mode 100644
index 00000000000..fe1cc7d5425
--- /dev/null
+++ b/app/models/list_user_preference.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class ListUserPreference < ApplicationRecord
+ belongs_to :user
+ belongs_to :list
+
+ validates :user, presence: true
+ validates :list, presence: true
+ validates :user_id, uniqueness: { scope: :list_id, message: "should have only one list preference per user" }
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 66d5286196e..c67c5c7bc8c 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -497,6 +497,7 @@ class Project < ApplicationRecord
# We require an alias to the project_mirror_data_table in order to use import_state in our queries
scope :joins_import_state, -> { joins("INNER JOIN project_mirror_data import_state ON import_state.project_id = projects.id") }
scope :for_group, -> (group) { where(group: group) }
+ scope :for_group_and_its_subgroups, ->(group) { where(namespace_id: group.self_and_descendants.select(:id)) }
class << self
# Searches for a list of projects based on the query given in `query`.
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 240c91da5b6..1ec04189482 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -186,9 +186,9 @@ class Todo < ApplicationRecord
def target_reference
if for_commit?
- target.reference_link_text(full: true)
+ target.reference_link_text
else
- target.to_reference(full: true)
+ target.to_reference
end
end
diff --git a/app/serializers/merge_request_noteable_entity.rb b/app/serializers/merge_request_noteable_entity.rb
new file mode 100644
index 00000000000..e22be6880bb
--- /dev/null
+++ b/app/serializers/merge_request_noteable_entity.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+class MergeRequestNoteableEntity < Grape::Entity
+ include RequestAwareEntity
+
+ # Currently this attr is exposed to be used in app/assets/javascripts/notes/stores/getters.js
+ # in order to determine whether a noteable is an issue or an MR
+ expose :merge_params
+
+ expose :state
+ expose :source_branch
+ expose :target_branch
+ expose :diff_head_sha
+
+ expose :create_note_path do |merge_request|
+ project_notes_path(merge_request.project, target_type: 'merge_request', target_id: merge_request.id)
+ end
+
+ expose :preview_note_path do |merge_request|
+ preview_markdown_path(merge_request.project, target_type: 'MergeRequest', target_id: merge_request.iid)
+ end
+
+ expose :supports_suggestion?, as: :can_receive_suggestion
+
+ expose :create_issue_to_resolve_discussions_path do |merge_request|
+ presenter(merge_request).create_issue_to_resolve_discussions_path
+ end
+
+ expose :new_blob_path do |merge_request|
+ if presenter(merge_request).can_push_to_source_branch?
+ project_new_blob_path(merge_request.source_project, merge_request.source_branch)
+ end
+ end
+
+ expose :current_user do
+ expose :can_create_note do |merge_request|
+ can?(current_user, :create_note, merge_request)
+ end
+
+ expose :can_update do |merge_request|
+ can?(current_user, :update_merge_request, merge_request)
+ end
+ end
+
+ private
+
+ delegate :current_user, to: :request
+
+ def presenter(merge_request)
+ @presenters ||= {}
+ @presenters[merge_request] ||= MergeRequestPresenter.new(merge_request, current_user: current_user) # rubocop: disable CodeReuse/Presenter
+ end
+end
diff --git a/app/serializers/merge_request_poll_widget_entity.rb b/app/serializers/merge_request_poll_widget_entity.rb
index 65132b4b215..cd33ffa702a 100644
--- a/app/serializers/merge_request_poll_widget_entity.rb
+++ b/app/serializers/merge_request_poll_widget_entity.rb
@@ -65,8 +65,6 @@ class MergeRequestPollWidgetEntity < IssuableEntity
end
end
- expose :supports_suggestion?, as: :can_receive_suggestion
-
expose :create_issue_to_resolve_discussions_path do |merge_request|
presenter(merge_request).create_issue_to_resolve_discussions_path
end
@@ -84,17 +82,9 @@ class MergeRequestPollWidgetEntity < IssuableEntity
presenter(merge_request).can_cherry_pick_on_current_merge_request?
end
- expose :can_create_note do |merge_request|
- can?(current_user, :create_note, merge_request)
- end
-
expose :can_create_issue do |merge_request|
can?(current_user, :create_issue, merge_request.project)
end
-
- expose :can_update do |merge_request|
- can?(current_user, :update_merge_request, merge_request)
- end
end
expose :can_push_to_source_branch do |merge_request|
diff --git a/app/serializers/merge_request_serializer.rb b/app/serializers/merge_request_serializer.rb
index bd2e682a122..aa67cd1f39e 100644
--- a/app/serializers/merge_request_serializer.rb
+++ b/app/serializers/merge_request_serializer.rb
@@ -13,6 +13,8 @@ class MergeRequestSerializer < BaseSerializer
MergeRequestSidebarExtrasEntity
when 'basic'
MergeRequestBasicEntity
+ when 'noteable'
+ MergeRequestNoteableEntity
else
# fallback to widget for old poll requests without `serializer` set
MergeRequestWidgetEntity
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index c8088608cb0..2f2c42a7387 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -3,10 +3,6 @@
class MergeRequestWidgetEntity < Grape::Entity
include RequestAwareEntity
- # Currently this attr is exposed to be used in app/assets/javascripts/notes/stores/getters.js
- # in order to determine whether a noteable is an issue or an MR
- expose :merge_params
-
expose :source_project_full_path do |merge_request|
merge_request.source_project&.full_path
end
@@ -35,18 +31,10 @@ class MergeRequestWidgetEntity < Grape::Entity
cached_widget_project_json_merge_request_path(merge_request.target_project, merge_request, format: :json)
end
- expose :create_note_path do |merge_request|
- project_notes_path(merge_request.project, target_type: 'merge_request', target_id: merge_request.id)
- end
-
expose :commit_change_content_path do |merge_request|
commit_change_content_project_merge_request_path(merge_request.project, merge_request)
end
- expose :preview_note_path do |merge_request|
- preview_markdown_path(merge_request.project, target_type: 'MergeRequest', target_id: merge_request.iid)
- end
-
expose :conflicts_docs_path do |merge_request|
help_page_path('user/project/merge_requests/resolve_conflicts.md')
end
diff --git a/app/services/base_count_service.rb b/app/services/base_count_service.rb
index ad1647842b8..cfad2dd9265 100644
--- a/app/services/base_count_service.rb
+++ b/app/services/base_count_service.rb
@@ -35,7 +35,7 @@ class BaseCountService
end
def cache_key
- raise NotImplementedError, 'cache_key must be implemented and return a String'
+ raise NotImplementedError, 'cache_key must be implemented and return a String, Array, or Hash'
end
# subclasses can override to add any specific options, such as
diff --git a/app/services/boards/lists/list_service.rb b/app/services/boards/lists/list_service.rb
index 5cf5f14a55b..1f20ec8df9e 100644
--- a/app/services/boards/lists/list_service.rb
+++ b/app/services/boards/lists/list_service.rb
@@ -6,7 +6,7 @@ module Boards
def execute(board)
board.lists.create(list_type: :backlog) unless board.lists.backlog.exists?
- board.lists.preload_associations
+ board.lists.preload_associations(current_user)
end
end
end
diff --git a/app/services/boards/lists/update_service.rb b/app/services/boards/lists/update_service.rb
new file mode 100644
index 00000000000..2ddeb6f0bd8
--- /dev/null
+++ b/app/services/boards/lists/update_service.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+module Boards
+ module Lists
+ class UpdateService < Boards::BaseService
+ def execute(list)
+ return not_authorized if preferences? && !can_read?(list)
+ return not_authorized if position? && !can_admin?(list)
+
+ if update_preferences(list) || update_position(list)
+ success(list: list)
+ else
+ error(list.errors.messages, 422)
+ end
+ end
+
+ def update_preferences(list)
+ return unless preferences?
+
+ list.update_preferences_for(current_user, preferences)
+ end
+
+ def update_position(list)
+ return unless position?
+
+ move_service = Boards::Lists::MoveService.new(parent, current_user, params)
+
+ move_service.execute(list)
+ end
+
+ def preferences
+ { collapsed: Gitlab::Utils.to_boolean(params[:collapsed]) }
+ end
+
+ def not_authorized
+ error("Not authorized", 403)
+ end
+
+ def preferences?
+ params.has_key?(:collapsed)
+ end
+
+ def position?
+ params.has_key?(:position)
+ end
+
+ def can_read?(list)
+ Ability.allowed?(current_user, :read_list, parent)
+ end
+
+ def can_admin?(list)
+ Ability.allowed?(current_user, :admin_list, parent)
+ end
+ end
+ end
+end
diff --git a/app/services/projects/lfs_pointers/lfs_link_service.rb b/app/services/projects/lfs_pointers/lfs_link_service.rb
index e3c956250f0..38de2af9c1e 100644
--- a/app/services/projects/lfs_pointers/lfs_link_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_link_service.rb
@@ -4,6 +4,8 @@
module Projects
module LfsPointers
class LfsLinkService < BaseService
+ BATCH_SIZE = 1000
+
# Accept an array of oids to link
#
# Returns an array with the oid of the existent lfs objects
@@ -18,16 +20,33 @@ module Projects
# rubocop: disable CodeReuse/ActiveRecord
def link_existing_lfs_objects(oids)
- existent_lfs_objects = LfsObject.where(oid: oids)
+ all_existing_objects = []
+ iterations = 0
+
+ LfsObject.where(oid: oids).each_batch(of: BATCH_SIZE) do |existent_lfs_objects|
+ next unless existent_lfs_objects.any?
+
+ iterations += 1
+ not_linked_lfs_objects = existent_lfs_objects.where.not(id: project.all_lfs_objects)
+ project.all_lfs_objects << not_linked_lfs_objects
- return [] unless existent_lfs_objects.any?
+ all_existing_objects += existent_lfs_objects.pluck(:oid)
+ end
- not_linked_lfs_objects = existent_lfs_objects.where.not(id: project.all_lfs_objects)
- project.all_lfs_objects << not_linked_lfs_objects
+ log_lfs_link_results(all_existing_objects.count, iterations)
- existent_lfs_objects.pluck(:oid)
+ all_existing_objects
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ def log_lfs_link_results(lfs_objects_linked_count, iterations)
+ Gitlab::Import::Logger.info(
+ class: self.class.name,
+ project_id: project.id,
+ project_path: project.full_path,
+ lfs_objects_linked_count: lfs_objects_linked_count,
+ iterations: iterations)
+ end
end
end
end
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index ee7223d6349..1b48b20e28b 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -67,7 +67,7 @@ module SystemNoteService
create_note(NoteSummary.new(noteable, project, author, body, action: 'assignee'))
end
- # Called when the assignees of an Issue is changed or removed
+ # Called when the assignees of an issuable is changed or removed
#
# issuable - Issuable object (responds to assignees)
# project - Project owning noteable
@@ -88,10 +88,12 @@ module SystemNoteService
def change_issuable_assignees(issuable, project, author, old_assignees)
unassigned_users = old_assignees - issuable.assignees
added_users = issuable.assignees.to_a - old_assignees
-
text_parts = []
- text_parts << "assigned to #{added_users.map(&:to_reference).to_sentence}" if added_users.any?
- text_parts << "unassigned #{unassigned_users.map(&:to_reference).to_sentence}" if unassigned_users.any?
+
+ Gitlab::I18n.with_default_locale do
+ text_parts << "assigned to #{added_users.map(&:to_reference).to_sentence}" if added_users.any?
+ text_parts << "unassigned #{unassigned_users.map(&:to_reference).to_sentence}" if unassigned_users.any?
+ end
body = text_parts.join(' and ')
diff --git a/app/views/admin/application_settings/_ip_limits.html.haml b/app/views/admin/application_settings/_ip_limits.html.haml
index 67a04fcf698..9512c1837bf 100644
--- a/app/views/admin/application_settings/_ip_limits.html.haml
+++ b/app/views/admin/application_settings/_ip_limits.html.haml
@@ -4,7 +4,7 @@
%fieldset
.form-group
.form-check
- = f.check_box :throttle_unauthenticated_enabled, class: 'form-check-input'
+ = f.check_box :throttle_unauthenticated_enabled, class: 'form-check-input', data: { qa_selector: 'throttle_unauthenticated_checkbox' }
= f.label :throttle_unauthenticated_enabled, class: 'form-check-label' do
Enable unauthenticated request rate limit
%span.form-text.text-muted
@@ -17,7 +17,7 @@
= f.number_field :throttle_unauthenticated_period_in_seconds, class: 'form-control'
.form-group
.form-check
- = f.check_box :throttle_authenticated_api_enabled, class: 'form-check-input'
+ = f.check_box :throttle_authenticated_api_enabled, class: 'form-check-input', data: { qa_selector: 'throttle_authenticated_api_checkbox' }
= f.label :throttle_authenticated_api_enabled, class: 'form-check-label' do
Enable authenticated API request rate limit
%span.form-text.text-muted
@@ -30,7 +30,7 @@
= f.number_field :throttle_authenticated_api_period_in_seconds, class: 'form-control'
.form-group
.form-check
- = f.check_box :throttle_authenticated_web_enabled, class: 'form-check-input'
+ = f.check_box :throttle_authenticated_web_enabled, class: 'form-check-input', data: { qa_selector: 'throttle_authenticated_web_checkbox' }
= f.label :throttle_authenticated_web_enabled, class: 'form-check-label' do
Enable authenticated web request rate limit
%span.form-text.text-muted
@@ -42,4 +42,4 @@
= f.label :throttle_authenticated_web_period_in_seconds, 'Rate limit period in seconds', class: 'label-bold'
= f.number_field :throttle_authenticated_web_period_in_seconds, class: 'form-control'
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "btn btn-success", data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/network.html.haml b/app/views/admin/application_settings/network.html.haml
index 26fd745f45f..3a4d901ca1d 100644
--- a/app/views/admin/application_settings/network.html.haml
+++ b/app/views/admin/application_settings/network.html.haml
@@ -13,7 +13,7 @@
.settings-content
= render 'performance'
-%section.settings.as-ip-limits.no-animate#js-ip-limits-settings{ class: ('expanded' if expanded_by_default?) }
+%section.settings.as-ip-limits.no-animate#js-ip-limits-settings{ class: ('expanded' if expanded_by_default?), data: { qa_selector: 'ip_limits_section' } }
.settings-header
%h4
= _('User and IP Rate Limits')
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index 8cdfc7369a0..fdb71d3a221 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -2,41 +2,49 @@
.todo-avatar
= author_avatar(todo, size: 40)
- .todo-item.todo-block
- .todo-title.title
+ .todo-item.todo-block.align-self-center
+ .todo-title
- unless todo.build_failed? || todo.unmergeable?
= todo_target_state_pill(todo)
- .title-item.author-name
+ %span.title-item.author-name.bold
- if todo.author
= link_to_author(todo, self_added: todo.self_added?)
- else
(removed)
- .title-item.action-name
+ %span.title-item.action-name
= todo_action_name(todo)
- .title-item.todo-label
+ %span.title-item.todo-label.todo-target-link
- if todo.target
= todo_target_link(todo)
- else
- (removed)
+ = _("(removed)")
+
+ %span.title-item.todo-target-title
+ = todo_target_title(todo)
+
+ %span.title-item.todo-project.todo-label
+ at
+ = todo_parent_path(todo)
- if todo.self_assigned?
- .title-item.action-name
+ %span.title-item.action-name
to yourself
- .title-item
+ %span.title-item
&middot;
- .title-item
+ %span.title-item.todo-timestamp
#{time_ago_with_tooltip(todo.created_at)}
= todo_due_date(todo)
- .todo-body
- .todo-note.break-word
- .md
- = first_line_in_markdown(todo, :body, 150, project: todo.project)
+ - if todo.note.present?
+ .todo-body
+ .todo-note.break-word
+ .md
+ = first_line_in_markdown(todo, :body, 150, project: todo.project)
- if todo.pending?
.todo-actions
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 0c8f86c2822..6d06bb246cb 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -14,7 +14,7 @@
.settings-content
= render 'groups/settings/general'
-%section.settings.gs-permissions.no-animate#js-permissions-settings{ class: ('expanded' if expanded) }
+%section.settings.gs-permissions.no-animate#js-permissions-settings{ class: ('expanded' if expanded), data: { qa_selector: 'permission_lfs_2fa_section' } }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only{ role: 'button' }
= _('Permissions, LFS, 2FA')
diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml
index 94a938021f9..c55730ccd31 100644
--- a/app/views/groups/settings/_permissions.html.haml
+++ b/app/views/groups/settings/_permissions.html.haml
@@ -31,4 +31,4 @@
= render 'groups/settings/two_factor_auth', f: f
= render_if_exists 'groups/member_lock_setting', f: f, group: @group
- = f.submit _('Save changes'), class: 'btn btn-success prepend-top-default js-dirty-submit'
+ = f.submit _('Save changes'), class: 'btn btn-success prepend-top-default js-dirty-submit', data: { qa_selector: 'save_permissions_changes_button' }
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 271b73326fa..68abfd3f61f 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -36,7 +36,6 @@
= stylesheet_link_tag "print", media: "print"
= stylesheet_link_tag "test", media: "all" if Rails.env.test?
= stylesheet_link_tag 'performance_bar' if performance_bar_enabled?
- = stylesheet_link_tag 'csslab' if Feature.enabled?(:csslab)
= stylesheet_link_tag "highlight/themes/#{user_color_scheme}", media: "all"
diff --git a/app/views/layouts/_snowplow.html.haml b/app/views/layouts/_snowplow.html.haml
index 5f5c5e984c5..d7ff5ad1094 100644
--- a/app/views/layouts/_snowplow.html.haml
+++ b/app/views/layouts/_snowplow.html.haml
@@ -7,23 +7,4 @@
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","#{asset_url('snowplow/sp.js')}","snowplow"));
- window.snowplow('newTracker', '#{Gitlab::SnowplowTracker::NAMESPACE}', '#{Gitlab::CurrentSettings.snowplow_collector_hostname}', {
- appId: '#{Gitlab::CurrentSettings.snowplow_site_id}',
- cookieDomain: '#{Gitlab::CurrentSettings.snowplow_cookie_domain}',
- userFingerprint: false,
- respectDoNotTrack: true,
- forceSecureTracker: true,
- post: true,
- contexts: { webPage: true },
- stateStorageStrategy: "localStorage"
- });
-
- window.snowplow('enableActivityTracking', 30, 30);
- window.snowplow('trackPageView');
-
-- return unless Feature.enabled?(:additional_snowplow_tracking, @group)
-
-= javascript_tag nonce: true do
- :plain
- window.snowplow('enableFormTracking');
- window.snowplow('enableLinkClickTracking');
+ window.snowplowOptions = #{Gitlab::Tracking.snowplow_options(@group).to_json}
diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml
index cb39c830170..9e92ced9f89 100644
--- a/app/views/layouts/nav/sidebar/_admin.html.haml
+++ b/app/views/layouts/nav/sidebar/_admin.html.haml
@@ -261,7 +261,7 @@
%span
= _('Metrics and profiling')
= nav_link(path: 'application_settings#network') do
- = link_to network_admin_application_settings_path, title: _('Network') do
+ = link_to network_admin_application_settings_path, title: _('Network'), data: { qa_selector: 'admin_settings_network_item' } do
%span
= _('Network')
- if template_exists?('admin/application_settings/geo')
diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index 48c9f19f89f..c1f4b3adfec 100644
--- a/app/views/layouts/nav/sidebar/_group.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
@@ -147,7 +147,7 @@
= _('Settings')
%li.divider.fly-out-top-item
= nav_link(path: 'groups#edit') do
- = link_to edit_group_path(@group), title: _('General') do
+ = link_to edit_group_path(@group), title: _('General'), data: { qa_selector: 'general_settings_link' } do
%span
= _('General')
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 02ecf816e90..48fea2bbecf 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -115,7 +115,7 @@
= _('List')
= nav_link(controller: :boards) do
- = link_to project_boards_path(@project), title: boards_link_text do
+ = link_to project_boards_path(@project), title: boards_link_text, data: { qa_selector: "issue_boards_link" } do
%span
= boards_link_text
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index 95c5eb32c7f..cf273aab108 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -9,6 +9,6 @@
= render "projects/blob/auxiliary_viewer", blob: blob
#blob-content-holder.blob-content-holder
- %article.file-holder{ class: ('use-csslab' if Feature.enabled?(:csslab)) }
+ %article.file-holder
= render 'projects/blob/header', blob: blob
= render 'projects/blob/content', blob: blob
diff --git a/app/views/projects/blob/preview.html.haml b/app/views/projects/blob/preview.html.haml
index 3e893343165..46e76e4d175 100644
--- a/app/views/projects/blob/preview.html.haml
+++ b/app/views/projects/blob/preview.html.haml
@@ -1,5 +1,5 @@
- if markup?(@blob.name)
- .file-content.md.md-file{ class: ('use-csslab' if Feature.enabled?(:csslab)) }
+ .file-content.md.md-file
= markup(@blob.name, @content)
- else
.diff-file
diff --git a/app/views/projects/blob/viewers/_markup.html.haml b/app/views/projects/blob/viewers/_markup.html.haml
index abc74b66e90..c71df29354b 100644
--- a/app/views/projects/blob/viewers/_markup.html.haml
+++ b/app/views/projects/blob/viewers/_markup.html.haml
@@ -1,4 +1,4 @@
- blob = viewer.blob
- context = blob.respond_to?(:rendered_markup) ? { rendered: blob.rendered_markup } : {}
-.file-content.md.md-file{ class: ('use-csslab' if Feature.enabled?(:csslab)) }
+.file-content.md.md-file
= markup(blob.name, blob.data, context)
diff --git a/app/views/projects/deployments/_deployment.html.haml b/app/views/projects/deployments/_deployment.html.haml
index 752be02443c..ef2ab4c698e 100644
--- a/app/views/projects/deployments/_deployment.html.haml
+++ b/app/views/projects/deployments/_deployment.html.haml
@@ -22,7 +22,8 @@
.table-section.section-15{ role: 'gridcell' }
.table-mobile-header{ role: 'rowheader' }= _("Created")
- %span.table-mobile-content= time_ago_with_tooltip(deployment.created_at)
+ - if deployment.deployed_at
+ %span.table-mobile-content= time_ago_with_tooltip(deployment.deployed_at)
.table-section.section-20.table-button-footer{ role: 'gridcell' }
.btn-group.table-action-buttons
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index af3bd8dcd69..ea166d622eb 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -6,6 +6,7 @@
- page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes
- suggest_changes_help_path = help_page_path('user/discussions/index.md', anchor: 'suggest-changes')
+- number_of_pipelines = @pipelines.size
.merge-request{ data: { mr_action: j(params[:tab].presence || 'show'), url: merge_request_path(@merge_request, format: :json), project_path: project_path(@merge_request.project), lock_version: @merge_request.lock_version } }
= render "projects/merge_requests/mr_title"
@@ -41,11 +42,11 @@
= tab_link_for @merge_request, :commits do
= _("Commits")
%span.badge.badge-pill= @commits_count
- - if @pipelines.any?
+ - if number_of_pipelines.nonzero?
%li.pipelines-tab
= tab_link_for @merge_request, :pipelines do
= _("Pipelines")
- %span.badge.badge-pill.js-pipelines-mr-count= @pipelines.size
+ %span.badge.badge-pill.js-pipelines-mr-count= number_of_pipelines
%li.diffs-tab.qa-diffs-tab
= tab_link_for @merge_request, :diffs do
= _("Changes")
@@ -63,21 +64,21 @@
%script.js-notes-data{ type: "application/json" }= initial_notes_data(true).to_json.html_safe
.issuable-discussion.js-vue-notes-event
#js-vue-mr-discussions{ data: { notes_data: notes_data(@merge_request).to_json,
- noteable_data: serialize_issuable(@merge_request),
+ noteable_data: serialize_issuable(@merge_request, serializer: 'noteable'),
noteable_type: 'MergeRequest',
target_type: 'merge_request',
help_page_path: suggest_changes_help_path,
- current_user_data: UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestUserEntity).to_json} }
+ current_user_data: @current_user_data} }
#commits.commits.tab-pane
-# This tab is always loaded via AJAX
#pipelines.pipelines.tab-pane
- - if @pipelines.any?
+ - if number_of_pipelines.nonzero?
= render 'projects/commit/pipelines_list', disable_initialization: true, endpoint: pipelines_project_merge_request_path(@project, @merge_request)
#js-diffs-app.diffs.tab-pane{ data: { "is-locked" => @merge_request.discussion_locked?,
endpoint: diffs_project_merge_request_path(@project, @merge_request, 'json', request.query_parameters),
help_page_path: suggest_changes_help_path,
- current_user_data: UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestUserEntity).to_json,
+ current_user_data: @current_user_data,
project_path: project_path(@merge_request.project),
changes_empty_state_illustration: image_path('illustrations/merge_request_changes_empty.svg'),
is_fluid_layout: fluid_layout.to_s,
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index da48cb207a4..f495b4eaf30 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -6,7 +6,7 @@
= render 'shared/snippets/header'
.project-snippets
- %article.file-holder.snippet-file-content{ class: ('use-csslab' if Feature.enabled?(:csslab)) }
+ %article.file-holder.snippet-file-content
= render 'shared/snippets/blob'
.row-content-block.top-block.content-component-block
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index c6197fe576e..51b7f2dd4b4 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -26,7 +26,7 @@
= (s_("WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}.") % { most_recent_link: most_recent_link, history_link: history_link }).html_safe
.prepend-top-default.append-bottom-default
- .md.md-file{ class: ('use-csslab' if Feature.enabled?(:csslab)) }
+ .md.md-file
= render_wiki_content(@page)
= render 'sidebar'
diff --git a/app/views/shared/boards/_show.html.haml b/app/views/shared/boards/_show.html.haml
index 4f0be117035..93fc839a371 100644
--- a/app/views/shared/boards/_show.html.haml
+++ b/app/views/shared/boards/_show.html.haml
@@ -4,7 +4,7 @@
- @no_container = true
- @content_class = "issue-boards-content js-focus-mode-board"
- breadcrumb_title _("Issue Boards")
-- page_title _("Boards")
+- page_title("#{board.name}", _("Boards"))
- content_for :page_specific_javascripts do
diff --git a/app/views/shared/runners/_form.html.haml b/app/views/shared/runners/_form.html.haml
index 559b5aa9c1e..24b4eae0c58 100644
--- a/app/views/shared/runners/_form.html.haml
+++ b/app/views/shared/runners/_form.html.haml
@@ -26,11 +26,6 @@
= f.check_box :locked, { class: 'form-check-input' }
%label.light{ for: :runner_locked }= _('When a runner is locked, it cannot be assigned to other projects')
.form-group.row
- = label_tag :token, class: 'col-form-label col-sm-2' do
- = _('Token')
- .col-sm-10
- = f.text_field :token, class: 'form-control', readonly: true
- .form-group.row
= label_tag :ip_address, class: 'col-form-label col-sm-2' do
= _('IP Address')
.col-sm-10
diff --git a/changelogs/unreleased/35060-remove-token-field.yml b/changelogs/unreleased/35060-remove-token-field.yml
new file mode 100644
index 00000000000..93a7b459dd8
--- /dev/null
+++ b/changelogs/unreleased/35060-remove-token-field.yml
@@ -0,0 +1,5 @@
+---
+title: Remove token field from runners edit form
+merge_request: 32231
+author:
+type: fixed
diff --git a/changelogs/unreleased/56130-operations-environments-shows-incorrect-deployment-date-for-manual-.yml b/changelogs/unreleased/56130-operations-environments-shows-incorrect-deployment-date-for-manual-.yml
new file mode 100644
index 00000000000..92f25ac07e2
--- /dev/null
+++ b/changelogs/unreleased/56130-operations-environments-shows-incorrect-deployment-date-for-manual-.yml
@@ -0,0 +1,6 @@
+---
+title: Update the timestamp in Operations > Environments to show correct deployment
+ date for manual deploy jobs
+merge_request: 32072
+author:
+type: fixed
diff --git a/changelogs/unreleased/57538-not-null-constraint-on-users-private-profile.yml b/changelogs/unreleased/57538-not-null-constraint-on-users-private-profile.yml
new file mode 100644
index 00000000000..bcbd8e3f11e
--- /dev/null
+++ b/changelogs/unreleased/57538-not-null-constraint-on-users-private-profile.yml
@@ -0,0 +1,5 @@
+---
+title: Setting NOT NULL constraint to users.private_profile column
+merge_request: 14838
+author:
+type: other
diff --git a/changelogs/unreleased/60141-mr-resolve-conflicts-file-headers-bad-positioning-on-scroll.yml b/changelogs/unreleased/60141-mr-resolve-conflicts-file-headers-bad-positioning-on-scroll.yml
new file mode 100644
index 00000000000..b6d6d596de9
--- /dev/null
+++ b/changelogs/unreleased/60141-mr-resolve-conflicts-file-headers-bad-positioning-on-scroll.yml
@@ -0,0 +1,5 @@
+---
+title: Fix file header style and position during scroll in a merge conflict resolution
+merge_request: 31991
+author:
+type: fixed
diff --git a/changelogs/unreleased/62284-follow-up-from-resolve-api-to-get-all-project-group-members-returns-duplicates.yml b/changelogs/unreleased/62284-follow-up-from-resolve-api-to-get-all-project-group-members-returns-duplicates.yml
new file mode 100644
index 00000000000..0c73f73c297
--- /dev/null
+++ b/changelogs/unreleased/62284-follow-up-from-resolve-api-to-get-all-project-group-members-returns-duplicates.yml
@@ -0,0 +1,5 @@
+---
+title: Uses projects_authorizations.access_level in MembersFinder
+merge_request: 28887
+author: Jacopo Beschi @jacopo-beschi
+type: fixed
diff --git a/changelogs/unreleased/63262-notes-are-persisted-with-the-user-s-locale.yml b/changelogs/unreleased/63262-notes-are-persisted-with-the-user-s-locale.yml
new file mode 100644
index 00000000000..e55beb9db09
--- /dev/null
+++ b/changelogs/unreleased/63262-notes-are-persisted-with-the-user-s-locale.yml
@@ -0,0 +1,5 @@
+---
+title: Do not translate system notes into author's language
+merge_request: 32264
+author:
+type: fixed
diff --git a/changelogs/unreleased/bump-pages-1-8.yml b/changelogs/unreleased/bump-pages-1-8.yml
new file mode 100644
index 00000000000..0201ff0fd5f
--- /dev/null
+++ b/changelogs/unreleased/bump-pages-1-8.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade pages to 1.8.0
+merge_request: 32334
+author:
+type: other
diff --git a/changelogs/unreleased/cluster_deployments.yml b/changelogs/unreleased/cluster_deployments.yml
new file mode 100644
index 00000000000..d854d16ea72
--- /dev/null
+++ b/changelogs/unreleased/cluster_deployments.yml
@@ -0,0 +1,5 @@
+---
+title: Add index to improve group cluster deployments query performance
+merge_request: 31988
+author:
+type: other
diff --git a/changelogs/unreleased/fix-search-input-dropdown.yml b/changelogs/unreleased/fix-search-input-dropdown.yml
new file mode 100644
index 00000000000..a86f7eacfdb
--- /dev/null
+++ b/changelogs/unreleased/fix-search-input-dropdown.yml
@@ -0,0 +1,5 @@
+---
+title: Fix top-nav search bar dropdown on xl displays
+merge_request: 31864
+author: Kemais Ehlers
+type: fixed
diff --git a/changelogs/unreleased/id-optimize-sql-requests-mr-show.yml b/changelogs/unreleased/id-optimize-sql-requests-mr-show.yml
new file mode 100644
index 00000000000..8b171a96316
--- /dev/null
+++ b/changelogs/unreleased/id-optimize-sql-requests-mr-show.yml
@@ -0,0 +1,5 @@
+---
+title: Reduce the number of SQL requests on MR-show
+merge_request: 32192
+author:
+type: performance
diff --git a/changelogs/unreleased/issue_40630.yml b/changelogs/unreleased/issue_40630.yml
new file mode 100644
index 00000000000..61cc773d5a9
--- /dev/null
+++ b/changelogs/unreleased/issue_40630.yml
@@ -0,0 +1,5 @@
+---
+title: Save collapsed option for board lists in database
+merge_request: 31069
+author:
+type: added
diff --git a/changelogs/unreleased/sh-fix-issue-move-api.yml b/changelogs/unreleased/sh-fix-issue-move-api.yml
new file mode 100644
index 00000000000..e98d04b02d9
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-move-api.yml
@@ -0,0 +1,5 @@
+---
+title: Fix moving issues API failing when text includes commit URLs
+merge_request: 32317
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-lfs-object-batches.yml b/changelogs/unreleased/sh-lfs-object-batches.yml
new file mode 100644
index 00000000000..09043e286be
--- /dev/null
+++ b/changelogs/unreleased/sh-lfs-object-batches.yml
@@ -0,0 +1,5 @@
+---
+title: Makes LFS object linker process OIDs in batches
+merge_request: 32268
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-upgrade-mermaid-8-2-4.yml b/changelogs/unreleased/sh-upgrade-mermaid-8-2-4.yml
new file mode 100644
index 00000000000..bdb64e43ecf
--- /dev/null
+++ b/changelogs/unreleased/sh-upgrade-mermaid-8-2-4.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade Mermaid to v8.2.4
+merge_request: 32186
+author:
+type: fixed
diff --git a/changelogs/unreleased/ss-add-board-name-to-page-title.yml b/changelogs/unreleased/ss-add-board-name-to-page-title.yml
new file mode 100644
index 00000000000..8a04972fa32
--- /dev/null
+++ b/changelogs/unreleased/ss-add-board-name-to-page-title.yml
@@ -0,0 +1,5 @@
+---
+title: Added board name to page title in boards view
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/todos-include-issue-mr-titles.yml b/changelogs/unreleased/todos-include-issue-mr-titles.yml
new file mode 100644
index 00000000000..a9fb9116070
--- /dev/null
+++ b/changelogs/unreleased/todos-include-issue-mr-titles.yml
@@ -0,0 +1,5 @@
+---
+title: Add Issue and Merge Request titles to Todo items
+merge_request: 30435
+author: Arun Kumar Mohan
+type: changed
diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-8-0.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-8-0.yml
new file mode 100644
index 00000000000..719a273b30c
--- /dev/null
+++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-8-0.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Runner Helm Chart to 0.8.0
+merge_request: 32289
+author:
+type: other
diff --git a/config/application.rb b/config/application.rb
index 294ed470298..81889561473 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -165,7 +165,6 @@ module Gitlab
config.assets.precompile << "locale/**/app.js"
config.assets.precompile << "emoji_sprites.css"
config.assets.precompile << "errors.css"
- config.assets.precompile << "csslab.css"
config.assets.precompile << "highlight/themes/*.css"
diff --git a/config/initializers/peek.rb b/config/initializers/peek.rb
index f9055285e5c..a3810be70b2 100644
--- a/config/initializers/peek.rb
+++ b/config/initializers/peek.rb
@@ -1,6 +1,7 @@
require 'peek/adapters/redis'
Peek::Adapters::Redis.prepend ::Gitlab::PerformanceBar::RedisAdapterWhenPeekEnabled
+Peek.singleton_class.prepend ::Gitlab::PerformanceBar::WithTopLevelWarnings
Rails.application.config.peek.adapter = :redis, { client: ::Redis.new(Gitlab::Redis::Cache.params) }
diff --git a/db/migrate/20190819131155_add_cluster_status_index_to_deployments.rb b/db/migrate/20190819131155_add_cluster_status_index_to_deployments.rb
new file mode 100644
index 00000000000..bfa91e33558
--- /dev/null
+++ b/db/migrate/20190819131155_add_cluster_status_index_to_deployments.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddClusterStatusIndexToDeployments < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :deployments, [:cluster_id, :status]
+ end
+
+ def down
+ remove_concurrent_index :deployments, [:cluster_id, :status]
+ end
+end
diff --git a/db/migrate/20190822181528_create_list_user_preferences.rb b/db/migrate/20190822181528_create_list_user_preferences.rb
new file mode 100644
index 00000000000..a7993818b50
--- /dev/null
+++ b/db/migrate/20190822181528_create_list_user_preferences.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class CreateListUserPreferences < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ create_table :list_user_preferences do |t|
+ t.references :user, index: true, null: false, foreign_key: { on_delete: :cascade }
+ t.references :list, index: true, null: false, foreign_key: { on_delete: :cascade }
+ t.timestamps_with_timezone null: false
+ t.boolean :collapsed
+ end
+
+ add_index :list_user_preferences, [:user_id, :list_id], unique: true
+ end
+end
diff --git a/db/migrate/20190826090628_remove_redundant_deployments_index.rb b/db/migrate/20190826090628_remove_redundant_deployments_index.rb
new file mode 100644
index 00000000000..6b009c17d64
--- /dev/null
+++ b/db/migrate/20190826090628_remove_redundant_deployments_index.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class RemoveRedundantDeploymentsIndex < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index :deployments, :cluster_id
+ end
+
+ def down
+ add_concurrent_index :deployments, :cluster_id
+ end
+end
diff --git a/db/migrate/20190828083843_add_index_to_ci_job_artifacts_on_project_id_for_security_reports.rb b/db/migrate/20190828083843_add_index_to_ci_job_artifacts_on_project_id_for_security_reports.rb
new file mode 100644
index 00000000000..5253f25aab4
--- /dev/null
+++ b/db/migrate/20190828083843_add_index_to_ci_job_artifacts_on_project_id_for_security_reports.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class AddIndexToCiJobArtifactsOnProjectIdForSecurityReports < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_job_artifacts,
+ :project_id,
+ name: "index_ci_job_artifacts_on_project_id_for_security_reports",
+ where: "file_type IN (5, 6, 7, 8)"
+ end
+
+ def down
+ remove_concurrent_index :ci_job_artifacts,
+ :project_id,
+ name: "index_ci_job_artifacts_on_project_id_for_security_reports"
+ end
+end
diff --git a/db/post_migrate/20190725080128_set_not_null_on_users_private_profile.rb b/db/post_migrate/20190725080128_set_not_null_on_users_private_profile.rb
new file mode 100644
index 00000000000..db42e949d3f
--- /dev/null
+++ b/db/post_migrate/20190725080128_set_not_null_on_users_private_profile.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class SetNotNullOnUsersPrivateProfile < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ Gitlab::BackgroundMigration.steal('MigrateNullPrivateProfileToFalse')
+
+ # rubocop:disable Migration/UpdateLargeTable
+ # rubocop:disable Migration/UpdateColumnInBatches
+ # Data has been migrated previously, count should be close to 0
+ update_column_in_batches(:users, :private_profile, false) do |table, query|
+ query.where(table[:private_profile].eq(nil))
+ end
+
+ change_column_null :users, :private_profile, false
+ end
+
+ def down
+ change_column_null :users, :private_profile, true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f30dad3d030..54774b0a65b 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: 2019_08_20_163320) do
+ActiveRecord::Schema.define(version: 2019_08_28_083843) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
@@ -658,6 +658,7 @@ ActiveRecord::Schema.define(version: 2019_08_20_163320) do
t.index ["file_store"], name: "index_ci_job_artifacts_on_file_store"
t.index ["job_id", "file_type"], name: "index_ci_job_artifacts_on_job_id_and_file_type", unique: true
t.index ["project_id"], name: "index_ci_job_artifacts_on_project_id"
+ t.index ["project_id"], name: "index_ci_job_artifacts_on_project_id_for_security_reports", where: "(file_type = ANY (ARRAY[5, 6, 7, 8]))"
end
create_table "ci_job_variables", force: :cascade do |t|
@@ -1145,7 +1146,7 @@ ActiveRecord::Schema.define(version: 2019_08_20_163320) do
t.integer "status", limit: 2, null: false
t.datetime_with_timezone "finished_at"
t.integer "cluster_id"
- t.index ["cluster_id"], name: "index_deployments_on_cluster_id"
+ t.index ["cluster_id", "status"], name: "index_deployments_on_cluster_id_and_status"
t.index ["created_at"], name: "index_deployments_on_created_at"
t.index ["deployable_type", "deployable_id"], name: "index_deployments_on_deployable_type_and_deployable_id"
t.index ["environment_id", "id"], name: "index_deployments_on_environment_id_and_id"
@@ -1921,6 +1922,17 @@ ActiveRecord::Schema.define(version: 2019_08_20_163320) do
t.datetime "updated_at"
end
+ create_table "list_user_preferences", force: :cascade do |t|
+ t.bigint "user_id", null: false
+ t.bigint "list_id", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.boolean "collapsed"
+ t.index ["list_id"], name: "index_list_user_preferences_on_list_id"
+ t.index ["user_id", "list_id"], name: "index_list_user_preferences_on_user_id_and_list_id", unique: true
+ t.index ["user_id"], name: "index_list_user_preferences_on_user_id"
+ end
+
create_table "lists", id: :serial, force: :cascade do |t|
t.integer "board_id", null: false
t.integer "label_id"
@@ -3499,7 +3511,7 @@ ActiveRecord::Schema.define(version: 2019_08_20_163320) do
t.integer "theme_id", limit: 2
t.integer "accepted_term_id"
t.string "feed_token"
- t.boolean "private_profile", default: false
+ t.boolean "private_profile", default: false, null: false
t.boolean "include_private_contributions"
t.string "commit_email"
t.boolean "auditor", default: false, null: false
@@ -3879,6 +3891,8 @@ ActiveRecord::Schema.define(version: 2019_08_20_163320) do
add_foreign_key "labels", "projects", name: "fk_7de4989a69", on_delete: :cascade
add_foreign_key "lfs_file_locks", "projects", on_delete: :cascade
add_foreign_key "lfs_file_locks", "users", on_delete: :cascade
+ add_foreign_key "list_user_preferences", "lists", on_delete: :cascade
+ add_foreign_key "list_user_preferences", "users", on_delete: :cascade
add_foreign_key "lists", "boards", name: "fk_0d3f677137", on_delete: :cascade
add_foreign_key "lists", "labels", name: "fk_7a5553d60f", on_delete: :cascade
add_foreign_key "lists", "milestones", on_delete: :cascade
diff --git a/doc/README.md b/doc/README.md
index f12c06199c2..9a0252cc334 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -358,7 +358,7 @@ The following documentation relates to the DevOps **Secure** stage:
| [Dependency Scanning](user/application_security/dependency_scanning/index.md) **(ULTIMATE)** | Analyze your dependencies for known vulnerabilities. |
| [Dynamic Application Security Testing (DAST)](user/application_security/dast/index.md) **(ULTIMATE)** | Analyze running web applications for known vulnerabilities. |
| [Group Security Dashboard](user/application_security/security_dashboard/index.md) **(ULTIMATE)** | View vulnerabilities in all the projects in a group and its subgroups. |
-| [License Compliance](user/application_security/license_management/index.md) **(ULTIMATE)** | Search your project's dependencies for their licenses. |
+| [License Compliance](user/application_security/license_compliance/index.md) **(ULTIMATE)** | Search your project's dependencies for their licenses. |
| [Project Security Dashboard](user/application_security/security_dashboard/index.md) **(ULTIMATE)** | View the latest security reports for your project. |
| [Static Application Security Testing (SAST)](user/application_security/sast/index.md) **(ULTIMATE)** | Analyze source code for known vulnerabilities. |
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
index 86dd398343b..7c14d4004db 100644
--- a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
+++ b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
@@ -32,7 +32,7 @@ For example, [Active Directory](https://technet.microsoft.com/en-us/library/hh83
We won't cover the installation and configuration of Windows Server or Active Directory Domain Services in this tutorial. There are a number of resources online to guide you through this process:
-- Install Windows Server 2012 - (_technet.microsoft.com_) - [Installing Windows Server 2012 ](https://technet.microsoft.com/en-us/library/jj134246(v=ws.11).aspx)
+- Install Windows Server 2012 - (_technet.microsoft.com_) - [Installing Windows Server 2012](https://technet.microsoft.com/en-us/library/jj134246(v=ws.11).aspx)
- Install Active Directory Domain Services (AD DS) (_technet.microsoft.com_)- [Install Active Directory Domain Services](https://technet.microsoft.com/windows-server-docs/identity/ad-ds/deploy/install-active-directory-domain-services--level-100-#BKMK_PS)
@@ -249,7 +249,7 @@ After configuring LDAP, basic authentication will be available. Users can then l
Users that are removed from the LDAP base group (e.g `OU=GitLab INT,DC=GitLab,DC=org`) will be **blocked** in GitLab. [More information](../ldap.md#security) on LDAP security.
-If `allow_username_or_email_login` is enabled in the LDAP configuration, GitLab will ignore everything after the first '@' in the LDAP username used on login. Example: The username `` jon.doe@example.com `` is converted to `jon.doe` when authenticating with the LDAP server. Disable this setting if you use `userPrincipalName` as the `uid`.
+If `allow_username_or_email_login` is enabled in the LDAP configuration, GitLab will ignore everything after the first '@' in the LDAP username used on login. Example: The username `jon.doe@example.com` is converted to `jon.doe` when authenticating with the LDAP server. Disable this setting if you use `userPrincipalName` as the `uid`.
## LDAP extended features on GitLab EE
diff --git a/doc/administration/auth/okta.md b/doc/administration/auth/okta.md
index 5524c3ba092..41745e8caae 100644
--- a/doc/administration/auth/okta.md
+++ b/doc/administration/auth/okta.md
@@ -98,20 +98,20 @@ Now that the Okta app is configured, it's time to enable it in GitLab.
>**Notes:**
>
>- Change the value for `assertion_consumer_service_url` to match the HTTPS endpoint
- of GitLab (append `users/auth/saml/callback` to the HTTPS URL of your GitLab
- installation to generate the correct value).
+ > of GitLab (append `users/auth/saml/callback` to the HTTPS URL of your GitLab
+ > installation to generate the correct value).
>
>- To get the `idp_cert_fingerprint` fingerprint, first download the
- certificate from the Okta app you registered and then run:
- `openssl x509 -in okta.cert -noout -fingerprint`. Substitute `okta.cert`
- with the location of your certificate.
+ > certificate from the Okta app you registered and then run:
+ > `openssl x509 -in okta.cert -noout -fingerprint`. Substitute `okta.cert`
+ > with the location of your certificate.
>
>- Change the value of `idp_sso_target_url`, with the value of the
- **Identity Provider Single Sign-On URL** from the step when you
- configured the Okta app.
+ > **Identity Provider Single Sign-On URL** from the step when you
+ > configured the Okta app.
>
>- Change the value of `issuer` to the value of the **Audience Restriction** from your Okta app configuration. This will identify GitLab
- to the IdP.
+ > to the IdP.
>
>- Leave `name_identifier_format` as-is.
diff --git a/doc/administration/geo/disaster_recovery/index.md b/doc/administration/geo/disaster_recovery/index.md
index ba95843b0b0..407539885a6 100644
--- a/doc/administration/geo/disaster_recovery/index.md
+++ b/doc/administration/geo/disaster_recovery/index.md
@@ -297,7 +297,7 @@ for another **primary** node. All the old replication settings will be overwritt
## Troubleshooting
-### I followed the disaster recovery instructions and now two-factor auth is broken!
+### I followed the disaster recovery instructions and now two-factor auth is broken
The setup instructions for Geo prior to 10.5 failed to replicate the
`otp_key_base` secret, which is used to encrypt the two-factor authentication
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index fe1557fd8b5..3ae92b07736 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -538,7 +538,7 @@ can simply reset the existing tracking database with:
sudo gitlab-rake geo:db:reset
```
-### Geo node has a database that is writable which is an indication it is not configured for replication with the primary node.
+### Geo node has a database that is writable which is an indication it is not configured for replication with the primary node
This error refers to a problem with the database replica on a **secondary** node,
which Geo expects to have access to. It usually means, either:
@@ -552,7 +552,7 @@ PostgreSQL instances:
- A read-only replica of the **primary** node.
- A regular, writable instance that holds replication metadata. That is, the Geo tracking database.
-### Geo node does not appear to be replicating the database from the primary node.
+### Geo node does not appear to be replicating the database from the primary node
The most common problems that prevent the database from replicating correctly are:
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index daec5f14e36..eab4b2c6eea 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -185,7 +185,7 @@ Check the directory layout on your Gitaly server to be sure.
```
1. Append the following to `/etc/gitlab/gitlab.rb` for each respective server:
-
+
For `gitaly1.internal`:
```
@@ -194,7 +194,7 @@ Check the directory layout on your Gitaly server to be sure.
{ 'name' => 'storage1' },
]
```
-
+
For `gitaly2.internal`:
```
@@ -226,7 +226,7 @@ Check the directory layout on your Gitaly server to be sure.
```
1. Append the following to `/home/git/gitaly/config.toml` for each respective server:
-
+
For `gitaly1.internal`:
```toml
@@ -236,7 +236,7 @@ Check the directory layout on your Gitaly server to be sure.
[[storage]]
name = 'storage1'
```
-
+
For `gitaly2.internal`:
```toml
@@ -262,12 +262,12 @@ Additionally, you need to
[disable Rugged if previously manually enabled](../high_availability/nfs.md#improving-nfs-performance-with-gitlab).
We assume that your `gitaly1.internal` Gitaly server can be reached at
-`gitaly1.internal:8075` from your GitLab server, and that Gitaly server
+`gitaly1.internal:8075` from your GitLab server, and that Gitaly server
can read and write to `/mnt/gitlab/default` and `/mnt/gitlab/storage1`.
We assume also that your `gitaly2.internal` Gitaly server can be reached at
-`gitaly2.internal:8075` from your GitLab server, and that Gitaly server
-can read and write to `/mnt/gitlab/storage2`.
+`gitaly2.internal:8075` from your GitLab server, and that Gitaly server
+can read and write to `/mnt/gitlab/storage2`.
**For Omnibus GitLab**
@@ -540,6 +540,7 @@ gitaly['concurrency'] = [
}
]
```
+
This will limit the number of in-flight RPC calls for the given RPC's.
The limit is applied per repository. In the example above, each on the
Gitaly server can have at most 20 simultaneous PostUploadPack calls in
@@ -729,4 +730,4 @@ To remove the proxy setting, run the following commands (depending on which vari
```bash
unset http_proxy
unset https_proxy
-``` \ No newline at end of file
+```
diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md
index 8818a9606de..0d1dd06871a 100644
--- a/doc/administration/high_availability/gitlab.md
+++ b/doc/administration/high_availability/gitlab.md
@@ -4,9 +4,9 @@ type: reference
# Configuring GitLab for Scaling and High Availability
-> **Note:** There is some additional configuration near the bottom for
- additional GitLab application servers. It's important to read and understand
- these additional steps before proceeding with GitLab installation.
+NOTE: **Note:** There is some additional configuration near the bottom for
+additional GitLab application servers. It's important to read and understand
+these additional steps before proceeding with GitLab installation.
1. If necessary, install the NFS client utility packages using the following
commands:
@@ -82,19 +82,19 @@ type: reference
1. [Enable monitoring](#enable-monitoring)
- > **Note:** To maintain uniformity of links across HA clusters, the `external_url`
+ NOTE: **Note:** To maintain uniformity of links across HA clusters, the `external_url`
on the first application server as well as the additional application
servers should point to the external url that users will use to access GitLab.
In a typical HA setup, this will be the url of the load balancer which will
route traffic to all GitLab application servers in the HA cluster.
- >
- > **Note:** When you specify `https` in the `external_url`, as in the example
+
+ NOTE: **Note:** When you specify `https` in the `external_url`, as in the example
above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
certificates are not present, Nginx will fail to start. See
[Nginx documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
for more information.
- >
- > **Note:** It is best to set the `uid` and `gid`s prior to the initial reconfigure
+
+ NOTE: **Note:** It is best to set the `uid` and `gid`s prior to the initial reconfigure
of GitLab. Omnibus will not recursively `chown` directories if set after the initial reconfigure.
## First GitLab application server
@@ -105,8 +105,8 @@ Do not run this on additional application servers.
1. Initialize the database by running `sudo gitlab-rake gitlab:setup`.
1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
-> **WARNING:** Only run this setup task on **NEW** GitLab instances because it
- will wipe any existing data.
+ CAUTION: **WARNING:** Only run this setup task on **NEW** GitLab instances because it
+ will wipe any existing data.
## Extra configuration for additional GitLab application servers
@@ -173,9 +173,10 @@ If you enable Monitoring, it must be enabled on **all** GitLab servers.
1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
-> **Warning:** After changing `unicorn['listen']` in `gitlab.rb`, and running `sudo gitlab-ctl reconfigure`,
- it can take an extended period of time for unicorn to complete reloading after receiving a `HUP`.
- For more information, see the [issue](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/4401).
+ CAUTION: **Warning:**
+ After changing `unicorn['listen']` in `gitlab.rb`, and running `sudo gitlab-ctl reconfigure`,
+ it can take an extended period of time for unicorn to complete reloading after receiving a `HUP`.
+ For more information, see the [issue](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/4401).
## Troubleshooting
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 16a193550a1..df6c554decb 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -1,7 +1,6 @@
# PlantUML & GitLab
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8537) in
-> GitLab 8.16.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8537) in GitLab 8.16.
When [PlantUML](http://plantuml.com) integration is enabled and configured in
GitLab we are able to create simple diagrams in AsciiDoc and Markdown documents
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index 9030c941cad..9b1efb610f8 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -338,3 +338,12 @@ installations from source.
[repocheck]: repository_checks.md
[Rack Attack]: ../security/rack_attack.md
[Rate Limit]: ../user/admin_area/settings/rate_limits_on_raw_endpoints.md
+
+## `database_load_balancing.log`
+
+Introduced in GitLab 12.3 for observability of [Database Load
+Balancing](https://docs.gitlab.com/ee/administration/database_load_balancing.html)
+when enabled. This file lives in
+`/var/log/gitlab/gitlab-rails/database_load_balancing.log` for Omnibus GitLab
+packages or in `/home/git/gitlab/log/database_load_balancing.log` for
+installations from source.
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index 4809bee0df6..ca48326c6d0 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -161,7 +161,16 @@ the `monitoring.sidekiq_exporter` configuration option in `gitlab.yml`.
| `geo_repositories_retrying_verification_count` | Gauge | 11.2 | Number of repositories verification failures that Geo is actively trying to correct on secondary | url |
| `geo_wikis_retrying_verification_count` | Gauge | 11.2 | Number of wikis verification failures that Geo is actively trying to correct on secondary | url |
-### Ruby metrics
+## Database load balancing metrics **(PREMIUM ONLY)**
+
+The following metrics are available:
+
+| Metric | Type | Since | Description |
+|:--------------------------------- |:--------- |:------------------------------------------------------------- |:-------------------------------------- |
+| `db_load_balancing_hosts` | Gauge | [12.3](https://gitlab.com/gitlab-org/gitlab-ee/issues/13630) | Current number of load balancing hosts |
+| `db_load_balancing_index` | Gauge | [12.3](https://gitlab.com/gitlab-org/gitlab-ee/issues/13630) | Current load balancing host index |
+
+## Ruby metrics
Some basic Ruby runtime metrics are available:
diff --git a/doc/administration/pages/source.md b/doc/administration/pages/source.md
index c77a1a9638f..fdfde22647d 100644
--- a/doc/administration/pages/source.md
+++ b/doc/administration/pages/source.md
@@ -343,21 +343,6 @@ world. Custom domains and TLS are supported.
1. Restart NGINX
1. [Restart GitLab][restart]
-## Change storage path
-
-Follow the steps below to change the default path where GitLab Pages' contents
-are stored.
-
-1. Pages are stored by default in `/var/opt/gitlab/gitlab-rails/shared/pages`.
- If you wish to store them in another location you must set it up in
- `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- gitlab_rails['pages_path'] = "/mnt/storage/pages"
- ```
-
-1. [Reconfigure GitLab][reconfigure]
-
## NGINX caveats
>**Note:**
@@ -468,7 +453,6 @@ than GitLab to prevent XSS attacks.
[NGINX configs]: https://gitlab.com/gitlab-org/gitlab-ee/tree/8-5-stable-ee/lib/support/nginx
[pages-readme]: https://gitlab.com/gitlab-org/gitlab-pages/blob/master/README.md
[pages-userguide]: ../../user/project/pages/index.md
-[reconfigure]: ../restart_gitlab.md#omnibus-gitlab-reconfigure
[restart]: ../restart_gitlab.md#installations-from-source
[gitlab-pages]: https://gitlab.com/gitlab-org/gitlab-pages/tree/v0.4.0
[gl-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/support/init.d/gitlab.default.example
diff --git a/doc/administration/raketasks/github_import.md b/doc/administration/raketasks/github_import.md
index ccd9c0afb1d..f8eecc97c33 100644
--- a/doc/administration/raketasks/github_import.md
+++ b/doc/administration/raketasks/github_import.md
@@ -1,6 +1,6 @@
# GitHub import
-> [Introduced]( https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10308) in GitLab 9.1.
+> [Introduced]( https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10308) in GitLab 9.1.
In order to retrieve and import GitHub repositories, you will need a
[GitHub personal access token](https://github.com/settings/tokens).
diff --git a/doc/administration/raketasks/ldap.md b/doc/administration/raketasks/ldap.md
index e880d76e756..d0ebe272b6d 100644
--- a/doc/administration/raketasks/ldap.md
+++ b/doc/administration/raketasks/ldap.md
@@ -19,8 +19,6 @@ sudo gitlab-rake gitlab:ldap:check
sudo -u git -H bundle exec rake gitlab:ldap:check RAILS_ENV=production
```
-------
-
By default, the task will return a sample of 100 LDAP users. Change this
limit by passing a number to the check task:
@@ -135,8 +133,6 @@ What is the old provider? Ex. 'ldapmain': ldapmain
What is the new provider? Ex. 'ldapcustom': ldapmycompany
```
-------
-
This tasks also accepts the `force` environment variable which will skip the
confirmation dialog:
diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md
index 8d0b5b42515..89335fcd2a8 100644
--- a/doc/administration/raketasks/maintenance.md
+++ b/doc/administration/raketasks/maintenance.md
@@ -260,7 +260,7 @@ To check the status of migrations, you can use the following rake task:
sudo gitlab-rake db:migrate:status
```
-This will output a table with a `Status` of `up` or `down` for
+This will output a table with a `Status` of `up` or `down` for
each Migration ID.
```bash
@@ -269,4 +269,4 @@ database: gitlabhq_production
Status Migration ID Migration Name
--------------------------------------------------
up migration_id migration_name
-``` \ No newline at end of file
+```
diff --git a/doc/administration/raketasks/uploads/migrate.md b/doc/administration/raketasks/uploads/migrate.md
index 86e8b763f51..d9b4c9b3369 100644
--- a/doc/administration/raketasks/uploads/migrate.md
+++ b/doc/administration/raketasks/uploads/migrate.md
@@ -108,7 +108,7 @@ sudo -u git -H bundle exec rake "gitlab:uploads:migrate[FileUploader, MergeReque
> Introduced in GitLab 12.3.
-To migrate all uploads created by legacy uploaders, run:
+To migrate all uploads created by legacy uploaders, run:
```shell
bundle exec rake gitlab:uploads:legacy:migrate
diff --git a/doc/administration/troubleshooting/elasticsearch.md b/doc/administration/troubleshooting/elasticsearch.md
index c4a7ba01fae..13b9c30b29d 100644
--- a/doc/administration/troubleshooting/elasticsearch.md
+++ b/doc/administration/troubleshooting/elasticsearch.md
@@ -266,9 +266,9 @@ ElasticSearch administrator.
Generally speaking, ensure:
-* The ElasticSearch server **is not** running on the same node as GitLab.
-* The ElasticSearch server have enough RAM and CPU cores.
-* That sharding **is** being used.
+- The ElasticSearch server **is not** running on the same node as GitLab.
+- The ElasticSearch server have enough RAM and CPU cores.
+- That sharding **is** being used.
Going into some more detail here, if ElasticSearch is running on the same server as GitLab, resource contention is **very** likely to occur. Ideally, ElasticSearch, which requires ample resources, should be running on its own server (maybe coupled with logstash and kibana).
diff --git a/doc/administration/troubleshooting/sidekiq.md b/doc/administration/troubleshooting/sidekiq.md
index 9b016c64e29..c41edb5dbfc 100644
--- a/doc/administration/troubleshooting/sidekiq.md
+++ b/doc/administration/troubleshooting/sidekiq.md
@@ -96,8 +96,9 @@ corresponding Ruby code where this is happening.
`gdb` can be another effective tool for debugging Sidekiq. It gives you a little
more interactive way to look at each thread and see what's causing problems.
-> **Note:** Attaching to a process with `gdb` will suspends the normal operation
- of the process (Sidekiq will not process jobs while `gdb` is attached).
+NOTE: **Note:**
+Attaching to a process with `gdb` will suspends the normal operation
+of the process (Sidekiq will not process jobs while `gdb` is attached).
Start by attaching to the Sidekiq PID:
@@ -280,10 +281,10 @@ has number of drawbacks, as mentioned in [Why Ruby’s Timeout is dangerous (and
> This is where the implications get interesting, and terrifying. This means that an exception can get raised:
>
-> * during a network request (ok, as long as the surrounding code is prepared to catch Timeout::Error)
-> * during the cleanup for the network request
-> * during a rescue block
-> * while creating an object to save to the database afterwards
-> * in any of your code, regardless of whether it could have possibly raised an exception before
+> - during a network request (ok, as long as the surrounding code is prepared to catch Timeout::Error)
+> - during the cleanup for the network request
+> - during a rescue block
+> - while creating an object to save to the database afterwards
+> - in any of your code, regardless of whether it could have possibly raised an exception before
>
> Nobody writes code to defend against an exception being raised on literally any line. That’s not even possible. So Thread.raise is basically like a sneak attack on your code that could result in almost anything. It would probably be okay if it were pure-functional code that did not modify any state. But this is Ruby, so that’s unlikely :)
diff --git a/doc/api/README.md b/doc/api/README.md
index 33394d46a2d..036b46da6e5 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -396,7 +396,7 @@ GET /api/v4/projects/diaspora%2Fdiaspora
NOTE: **Note:**
A project's **path** is not necessarily the same as its **name**. A
-project's path can found in the project's URL or in the project's settings
+project's path can be found in the project's URL or in the project's settings
under **General > Advanced > Change path**.
## Branches and tags name encoding
@@ -422,7 +422,7 @@ We can call the API with `array` and `hash` types parameters as shown below:
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
-d "import_sources[]=github" \
-d "import_sources[]=bitbucket" \
-"https://gitlab.example.com/api/v4/some_endpoint
+https://gitlab.example.com/api/v4/some_endpoint
```
### `hash`
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index d99a4c37d72..e87270f884a 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -516,4 +516,3 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `username` | String! | |
| `avatarUrl` | String! | |
| `webUrl` | String! | |
-
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 0d500f783aa..d7f5b1b463b 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -158,6 +158,7 @@ Parameters:
| `with_shared` | boolean | no | Include projects shared to this group. Default is `true` |
| `include_subgroups` | boolean | no | Include projects in subgroups of this group. Default is `false` |
| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
+| `with_security_reports` | boolean | no | **(ULTIMATE)** Return only projects that have security reports artifacts present in any of their builds. This means "projects with security reports enabled". Default is `false` |
Example response:
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index c1588f2292a..58d9d1cd4d8 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -81,6 +81,27 @@ Parameters:
- `code` (required) - The content of a snippet
- `visibility` (required) - The snippet's visibility
+Example request:
+
+```bash
+curl --request POST https://gitlab.com/api/v4/projects/:id/snippets \
+ --header "PRIVATE-TOKEN: <your access token>" \
+ --header "Content-Type: application/json" \
+ -d @snippet.json
+```
+
+`snippet.json` used in the above example request:
+
+```json
+{
+ "title" : "Example Snippet Title",
+ "description" : "More verbose snippet description",
+ "file_name" : "example.txt",
+ "code" : "source code \n with multiple lines\n",
+ "visibility" : "private"
+}
+```
+
## Update snippet
Updates an existing project snippet. The user must have permission to change an existing snippet.
@@ -99,6 +120,27 @@ Parameters:
- `code` (optional) - The content of a snippet
- `visibility` (optional) - The snippet's visibility
+Example request:
+
+```bash
+curl --request PUT https://gitlab.com/api/v4/projects/:id/snippets \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ --header "Content-Type: application/json" \
+ -d @snippet.json
+```
+
+`snippet.json` used in the above example request:
+
+```json
+{
+ "title" : "Updated Snippet Title",
+ "description" : "More verbose snippet description",
+ "file_name" : "new_filename.txt",
+ "code" : "updated source code \n with multiple lines\n",
+ "visibility" : "private"
+}
+```
+
## Delete snippet
Deletes an existing project snippet. This returns a `204 No Content` status code if the operation was successfully or `404` if the resource was not found.
@@ -112,6 +154,13 @@ Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `snippet_id` (required) - The ID of a project's snippet
+Example request:
+
+```bash
+curl --request DELETE https://gitlab.com/api/v4/projects/:id/snippets \
+ --header "PRIVATE-TOKEN: <your_access_token>"
+```
+
## Snippet content
Returns the raw project snippet as plain text.
@@ -125,6 +174,13 @@ Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `snippet_id` (required) - The ID of a project's snippet
+Example request:
+
+```bash
+curl --request GET https://gitlab.com/api/v4/projects/:id/snippets/:snippet_id/raw \
+ --header "PRIVATE-TOKEN: <your_access_token>"
+```
+
## Get user agent details
> [Introduced][ce-29508] in GitLab 9.4.
@@ -140,6 +196,8 @@ GET /projects/:id/snippets/:snippet_id/user_agent_detail
| `id` | Integer | yes | The ID of a project |
| `snippet_id` | Integer | yes | The ID of a snippet |
+Example request:
+
```bash
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/snippets/2/user_agent_detail
```
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 4be13204227..90d0e6a7dc6 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -131,7 +131,7 @@ Its feature set is listed on the table below according to DevOps stages.
| **Secure** ||
| [Container Scanning](../user/application_security/container_scanning/index.md) **(ULTIMATE)** | Check your Docker containers for known vulnerabilities.|
| [Dependency Scanning](../user/application_security/dependency_scanning/index.md) **(ULTIMATE)** | Analyze your dependencies for known vulnerabilities. |
-| [License Compliance](../user/application_security/license_management/index.md) **(ULTIMATE)** | Search your project dependencies for their licenses. |
+| [License Compliance](../user/application_security/license_compliance/index.md) **(ULTIMATE)** | Search your project dependencies for their licenses. |
| [Security Test reports](../user/project/merge_requests/index.md#security-reports-ultimate) **(ULTIMATE)** | Check for app vulnerabilities. |
## Examples
diff --git a/doc/ci/directed_acyclic_graph/index.md b/doc/ci/directed_acyclic_graph/index.md
index 1c38c08b7cb..60e3120ba33 100644
--- a/doc/ci/directed_acyclic_graph/index.md
+++ b/doc/ci/directed_acyclic_graph/index.md
@@ -36,7 +36,7 @@ It has a pipeline that looks like the following:
| ----- | ---- | ------ |
| build_a | test_a | deploy_a |
| build_b | test_b | deploy_b |
-| build_c | test_c | deploy_c |
+| build_c | test_c | deploy_c |
| build_d | test_d | deploy_d |
Using a DAG, you can relate the `_a` jobs to each other separately from the `_b` jobs,
diff --git a/doc/ci/examples/license_management.md b/doc/ci/examples/license_management.md
index 53e38111bf3..0d12c9a20f2 100644
--- a/doc/ci/examples/license_management.md
+++ b/doc/ci/examples/license_management.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../../user/application_security/license_management/index.md'
+redirect_to: '../../user/application_security/license_compliance/index.md'
---
-This document was moved to [another location](../../user/application_security/license_management/index.md).
+This document was moved to [another location](../../user/application_security/license_compliance/index.md).
diff --git a/doc/ci/jenkins/index.md b/doc/ci/jenkins/index.md
index f8a3fab88e3..ace1204511e 100644
--- a/doc/ci/jenkins/index.md
+++ b/doc/ci/jenkins/index.md
@@ -32,7 +32,7 @@ There are some high level differences between the products worth mentioning:
## Groovy vs. YAML
-Jenkins Pipelines are based on [Groovy](https://groovy-lang.org/), so the pipeline specification is written as code.
+Jenkins Pipelines are based on [Groovy](https://groovy-lang.org/), so the pipeline specification is written as code.
GitLab works a bit differently, we use the more highly structured [YAML](https://yaml.org/) format, which
places scripting elements inside of `script:` blocks separate from the pipeline specification itself.
@@ -56,7 +56,7 @@ rspec:
- .in-docker
script:
- rake rspec
-```
+```
## Artifact publishing
@@ -143,7 +143,7 @@ default:
GitLab CI also lets you define stages, but is a little bit more free-form to configure. The GitLab [`stages` keyword](../yaml/README.md#stages)
is a top level setting that enumerates the list of stages, but you are not required to nest individual jobs underneath
-the `stages` section. Any job defined in the `.gitlab-ci.yml` can be made a part of any stage through use of the
+the `stages` section. Any job defined in the `.gitlab-ci.yml` can be made a part of any stage through use of the
[`stage:` keyword](../yaml/README.md#stage).
Note that, unless otherwise specified, every pipeline is instantiated with a `build`, `test`, and `deploy` stage
@@ -229,4 +229,4 @@ our very powerful [`only/except` rules system](../yaml/README.md#onlyexcept-basi
```yaml
my_job:
only: branches
-``` \ No newline at end of file
+```
diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
index 80a1c264bc4..7998b0452be 100644
--- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
@@ -141,4 +141,4 @@ please ask administrator to execute the following commands:
> sudo gitlab-rails console # Login to Rails console of GitLab instance.
> Feature.enabled?(:merge_trains_enabled) # Check if it's enabled or not.
> Feature.disable(:merge_trains_enabled) # Disable the feature flag.
-``` \ No newline at end of file
+```
diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md
index 269bd5c3428..abb503c6516 100644
--- a/doc/ci/runners/README.md
+++ b/doc/ci/runners/README.md
@@ -156,8 +156,7 @@ An admin can enable/disable a specific Runner for projects:
## Protected Runners
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13194)
-> in GitLab 10.0.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13194) in GitLab 10.0.
You can protect Runners from revealing sensitive information.
Whenever a Runner is protected, the Runner picks only jobs created on
diff --git a/doc/ci/services/mysql.md b/doc/ci/services/mysql.md
index 9ea113969c8..ce69a7df885 100644
--- a/doc/ci/services/mysql.md
+++ b/doc/ci/services/mysql.md
@@ -27,8 +27,8 @@ variables:
NOTE: **Note:**
The `MYSQL_DATABASE` and `MYSQL_ROOT_PASSWORD` variables can't be set in the GitLab UI.
-To set them, assign them to a variable [in the UI](../variables/README.md#via-the-ui),
-and then assign that variable to the
+To set them, assign them to a variable [in the UI](../variables/README.md#via-the-ui),
+and then assign that variable to the
`MYSQL_DATABASE` and `MYSQL_ROOT_PASSWORD` variables in your `.gitlab-ci.yml`.
And then configure your application to use the database, for example:
diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md
index 2a382f18038..f62a4660713 100644
--- a/doc/ci/triggers/README.md
+++ b/doc/ci/triggers/README.md
@@ -58,8 +58,7 @@ Read more about the [pipelines trigger API][trigapi].
#### When a pipeline depends on the artifacts of another pipeline **(PREMIUM)**
-> The use of `CI_JOB_TOKEN` in the artifacts download API was [introduced][ee-2346]
- in [GitLab Premium][ee] 9.5.
+> The use of `CI_JOB_TOKEN` in the artifacts download API was [introduced][ee-2346] in [GitLab Premium][ee] 9.5.
With the introduction of dependencies between different projects, one of
them may need to access artifacts created by a previous one. This process
@@ -271,7 +270,7 @@ Old triggers, created before GitLab 9.0 will be marked as legacy.
Triggers with the legacy label do not have an associated user and only have
access to the current project. They are considered deprecated and will be
-removed with one of the future versions of GitLab.
+removed with one of the future versions of GitLab.
[ee-2017]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2017
[ee-2346]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2346
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 1368764bcf8..7a60dedc206 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -1699,7 +1699,7 @@ dashboards.
> Introduced in GitLab 11.5. Requires GitLab Runner 11.5 and above.
-The `license_management` report collects [Licenses](../../user/project/merge_requests/license_management.md)
+The `license_management` report collects [Licenses](../../user/application_security/license_compliance/index.md)
as artifacts.
The collected License Compliance report will be uploaded to GitLab as an artifact and will
@@ -1899,9 +1899,8 @@ job1:
### `retry`
-> [Introduced][ce-12909] in GitLab 9.5.
-> [Behaviour expanded](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21758)
-> in GitLab 11.5 to control on which failures to retry.
+> - [Introduced][ce-12909] in GitLab 9.5.
+> - [Behaviour expanded](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21758) in GitLab 11.5 to control on which failures to retry.
`retry` allows you to configure how many times a job is going to be retried in
case of a failure.
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index 853882e8642..887f17b05b8 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -65,7 +65,7 @@ Sign up for the mailing list, answer GitLab questions on StackOverflow or
respond in the IRC channel. You can also sign up on [CodeTriage][codetriage] to help with
the remaining issues on the GitHub issue tracker.
-## I want to contribute!
+## I want to contribute
If you want to contribute to GitLab,
[issues with the `Accepting merge requests` label](issue_workflow.md#label-for-community-contributors)
@@ -93,26 +93,20 @@ When submitting code to GitLab, you may feel that your contribution requires the
When your code contains more than 500 changes, any major breaking changes, or an external library, `@mention` a maintainer in the merge request. If you are not sure who to mention, the reviewer will add one early in the merge request process.
-## Issues
+## Issues workflow
-This [documentation](issue_workflow.md) outlines the current issue process.
+This [documentation](issue_workflow.md) outlines the current issue workflow:
-- [Type labels](issue_workflow.md#type-labels)
-- [Subject labels](issue_workflow.md#subject-labels)
-- [Team labels](issue_workflow.md#team-labels)
-- [Release Scoping labels](issue_workflow.md#release-scoping-labels)
-- [Priority labels](issue_workflow.md#priority-labels)
-- [Severity labels](issue_workflow.md#severity-labels)
-- [Label for community contributors](issue_workflow.md#label-for-community-contributors)
+- [Issue tracker guidelines](issue_workflow.md#issue-tracker-guidelines)
- [Issue triaging](issue_workflow.md#issue-triaging)
+- [Labels](issue_workflow.md#labels)
- [Feature proposals](issue_workflow.md#feature-proposals)
-- [Issue tracker guidelines](issue_workflow.md#issue-tracker-guidelines)
- [Issue weight](issue_workflow.md#issue-weight)
- [Regression issues](issue_workflow.md#regression-issues)
- [Technical and UX debt](issue_workflow.md#technical-and-ux-debt)
-- [Stewardship](issue_workflow.md#stewardship)
+- [Technical debt in follow-up issues](issue_workflow.md#technical-debt-in-follow-up-issues)
-## Merge requests
+## Merge requests workflow
This [documentation](merge_request_workflow.md) outlines the current merge request process.
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index b2e3ef7bf63..f00a810ec42 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -1,17 +1,51 @@
-# Workflow labels
+# Issues workflow
-To allow for asynchronous issue handling, we use [milestones][milestones-page]
+## Issue tracker guidelines
+
+**[Search the issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues)** for similar entries before
+submitting your own, there's a good chance somebody else had the same issue or
+feature proposal. Show your support with an award emoji and/or join the
+discussion.
+
+Please submit bugs using the ['Bug' issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Bug.md) provided on the issue tracker.
+The text in the parenthesis is there to help you with what to include. Omit it
+when submitting the actual issue. You can copy-paste it and then edit as you
+see fit.
+
+## Issue triaging
+
+Our issue triage policies are [described in our handbook](https://about.gitlab.com/handbook/engineering/issue-triage/).
+You are very welcome to help the GitLab team triage issues.
+We also organize [issue bash events](https://gitlab.com/gitlab-org/gitlab-ce/issues/17815)
+once every quarter.
+
+The most important thing is making sure valid issues receive feedback from the
+development team. Therefore the priority is mentioning developers that can help
+on those issues. Please select someone with relevant experience from the
+[GitLab team](https://about.gitlab.com/team/).
+If there is nobody mentioned with that expertise look in the commit history for
+the affected files to find someone.
+
+We also use [GitLab Triage](https://gitlab.com/gitlab-org/gitlab-triage) to
+automate some triaging policies. This is currently set up as a
+[scheduled pipeline](https://gitlab.com/gitlab-org/quality/triage-ops/pipeline_schedules/10512/edit)
+running on [quality/triage-ops](https://gitlab.com/gitlab-org/quality/triage-ops) project.
+
+## Labels
+
+To allow for asynchronous issue handling, we use [milestones](https://gitlab.com/groups/gitlab-org/-/milestones)
and [labels](https://gitlab.com/gitlab-org/gitlab-ce/-/labels). Leads and product managers handle most of the
scheduling into milestones. Labelling is a task for everyone.
Most issues will have labels for at least one of the following:
- Type: ~feature, ~bug, ~backstage, etc.
-- Subject: ~wiki, ~"Container Registry", ~ldap, ~api, etc.
-- Team: ~Documentation, ~Delivery, etc.
- Stage: ~"devops::plan", ~"devops::create", etc.
-- Group: ~"group::source code" ~"group::knowledge" ~"group::editor", etc.
+- Group: ~"group::source code", ~"group::knowledge", ~"group::editor", etc.
+- Category: ~"Category:Code Analytics", ~"Category:DevOps Score", ~"Category:Templates", etc.
+- Feature: ~wiki, ~ldap, ~api, ~issues, ~"merge requests", etc.
- Department: ~UX, ~Quality
+- Team: ~Documentation, ~Delivery
- Specialization: ~frontend, ~backend
- Release Scoping: ~Deliverable, ~Stretch, ~"Next Patch Release"
- Priority: ~P1, ~P2, ~P3, ~P4
@@ -23,14 +57,18 @@ All labels, their meaning and priority are defined on the
If you come across an issue that has none of these, and you're allowed to set
labels, you can _always_ add the team and type, and often also the subject.
-[milestones-page]: https://gitlab.com/groups/gitlab-org/-/milestones
-
-## Type labels
+### Type labels
Type labels are very important. They define what kind of issue this is. Every
-issue should have one or more.
+issue should have one and only one.
+
+The current type labels are:
-Examples of type labels are ~feature, ~bug, ~backstage and ~security
+- ~feature
+- ~bug
+- ~backstage
+- ~"support request"
+- ~meta
A number of type labels have a priority assigned to them, which automatically
makes them float to the top, depending on their importance.
@@ -38,68 +76,74 @@ makes them float to the top, depending on their importance.
Type labels are always lowercase, and can have any color, besides blue (which is
already reserved for subject labels).
-The descriptions on the [labels page](https://gitlab.com/gitlab-org/gitlab-ce/-/labels) explain what falls under each type label.
+The descriptions on the [labels page](https://gitlab.com/groups/gitlab-org/-/labels)
+explain what falls under each type label.
-## Subject labels
+### Facet labels
-Subject labels are labels that define what area or feature of GitLab this issue
-hits. They are not always necessary, but very convenient.
+Sometimes it's useful to refine the type of an issue. In those cases, you can
+add facet labels.
-Subject labels are now used to infer and apply relevant group and devops stage
-labels. Please apply them whenever possible to facilitate accurate matching.
-Please refer to [this merge request][inferred-labels] for more information.
+Following is a non-exhaustive list of facet labels:
-Examples of subject labels are ~wiki, ~ldap, ~api,
-~issues, ~"merge requests", ~labels, and ~"Container Registry".
+- ~enhancement: This label can refine an issue that has the ~feature label.
+- ~"master:broken": This label can refine an issue that has the ~bug label.
+- ~"master:flaky": This label can refine an issue that has the ~bug label.
+- ~"technical debt": This label can refine an issue that has the ~backstage label.
+- ~"static analysis": This label can refine an issue that has the ~backstage label.
+- ~"ci-build": This label can refine an issue that has the ~backstage label.
+- ~performance: A performance issue could describe a ~bug or a ~feature.
+- ~security: A security issue could describe a ~bug or a ~feature.
+- ~database: A database issue could describe a ~bug or a ~feature.
+- ~customer: This relates to an issue that was created by a customer, or that is of interest for a customer.
-If you are an expert in a particular area, it makes it easier to find issues to
-work on. You can also subscribe to those labels to receive an email each time an
-issue is labeled with a subject label corresponding to your expertise.
+### Stage labels
-Subject labels are always all-lowercase.
+Stage labels specify which [stage](https://about.gitlab.com/handbook/product/categories/#hierarchy) the issue belongs to.
-## Team labels
-
-**Important**: Most of the historical team labels (e.g. Manage, Plan etc.) are
-now deprecated in favor of [Group labels](#group-labels) and [Stage labels](#stage-labels).
-
-Team labels specify what team is responsible for this issue.
-Assigning a team label makes sure issues get the attention of the appropriate
-people.
+#### Naming and color convention
-The current team labels are:
+Stage labels respects the `devops::<stage_key>` naming convention.
+`<stage_key>` is the stage key as it is in the single source of truth for stages at
+<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml>
+with `_` replaced with ` `.
-- ~Delivery
-- ~Documentation
-- ~Quality
+For instance, the "Manage" stage is represented by the ~"devops::manage" label in
+the `gitlab-org` group since its key under `stages` is `manage`.
-Team labels are always capitalized so that they show up as the first label for
-any issue.
+The current stage labels can be found by [searching the labels list for `devops::`](https://gitlab.com/groups/gitlab-org/-/labels?search=devops::).
-## Stage labels
+These labels are [scoped labels](../../user/project/labels.md#scoped-labels-premium)
+and thus are mutually exclusive.
-Stage labels specify which [DevOps stage][devops-stages] the issue belongs to.
+The Stage labels are used to generate the [direction pages](https://about.gitlab.com/direction/) automatically.
-The current stage labels can be found by [searching the labels list for `devops::`](https://gitlab.com/groups/gitlab-org/-/labels?search=devops%3A%3A).
+### Group labels
-These labels are [scoped labels](../../user/project/labels.md#scoped-labels-premium)
-and thus are mutually exclusive.
+Group labels specify which [groups](https://about.gitlab.com/company/team/structure/#product-groups) the issue belongs to.
-The Stage labels are used to generate the [direction pages][direction-pages] automatically.
+It's highly recommended to add a group label, as it's used by our triage
+automation to
+[infer the correct stage label](https://about.gitlab.com/handbook/engineering/quality/triage-operations/#auto-labelling-of-issues).
-[devops-stages]: https://about.gitlab.com/direction/#devops-stages
-[direction-pages]: https://about.gitlab.com/direction/
+#### Naming and color convention
-## Group labels
+Group labels respects the `group::<group_key>` naming convention and
+their color is `#A8D695`.
+`<group_key>` is the group key as it is in the single source of truth for groups at
+<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml>,
+with `_` replaced with ` `.
-Group labels specify which [groups][structure-groups] the issue belongs to.
+For instance, the "Continuous Integration" group is represented by the
+~"group::continuous integration" label in the `gitlab-org` group since its key
+under `stages.manage.groups` is `continuous_integration`.
-The current group labels can be found by [searching the labels list for `group::`](https://gitlab.com/groups/gitlab-org/-/labels?search=group%3A%3A).
+The current group labels can be found by [searching the labels list for `group::`](https://gitlab.com/groups/gitlab-org/-/labels?search=group::).
These labels are [scoped labels](../../user/project/labels.md#scoped-labels-premium)
and thus are mutually exclusive.
-You can find the groups listed in the [Product Stages, Groups, and Categories][product-categories] page.
+You can find the groups listed in the [Product Stages, Groups, and Categories](https://about.gitlab.com/handbook/product/categories/) page.
We use the term group to map down product requirements from our product stages.
As a team needs some way to collect the work their members are planning to be assigned to, we use the `~group::` labels to do so.
@@ -110,24 +154,95 @@ any issue can be picked up by any group, depending on current priorities. For ex
We also use stage and group labels to help quantify our [throughput](https://about.gitlab.com/handbook/engineering/management/throughput).
Please read [Stage and Group labels in Throughtput](https://about.gitlab.com/handbook/engineering/management/throughput/#stage-and-group-labels-in-throughput) for more information on how the labels are used in this context.
-[structure-groups]: https://about.gitlab.com/company/team/structure/#groups
-[product-categories]: https://about.gitlab.com/handbook/product/categories/
+### Category labels
+
+From the handbook's
+[Product stages, groups, and categories](https://about.gitlab.com/handbook/product/categories/#hierarchy)
+page:
+
+> Categories are high-level capabilities that may be a standalone product at
+another company. e.g. Portfolio Management.
+
+It's highly recommended to add a category label, as it's used by our triage
+automation to
+[infer the correct group and stage labels](https://about.gitlab.com/handbook/engineering/quality/triage-operations/#auto-labelling-of-issues).
+
+If you are an expert in a particular area, it makes it easier to find issues to
+work on. You can also subscribe to those labels to receive an email each time an
+issue is labeled with a category label corresponding to your expertise.
+
+#### Naming and color convention
+
+Category labels respects the `Category:<Category Name>` naming convention and
+their color is `#428BCA`.
+`<Category Name>` is the category name as it is in the single source of truth for categories at
+<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml>.
+
+For instance, the "Code Analytics" category is represented by the
+~"Category:Code Analytics" label in the `gitlab-org` group since its
+`code_analytics.name` value is "Code Analytics".
+
+If a category's label doesn't respect this naming convention, it should be specified
+with [the `label` attribute](https://about.gitlab.com/handbook/marketing/website/#category-attributes)
+in <https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml>.
+
+### Feature labels
+
+From the handbook's
+[Product stages, groups, and categories](https://about.gitlab.com/handbook/product/categories/#hierarchy)
+page:
+
+> Features: Small, discrete functionalities. e.g. Issue weights. Some common
+features are listed within parentheses to facilitate finding responsible PMs by keyword.
+
+It's highly recommended to add a feature label if no category label applies, as
+it's used by our triage automation to
+[infer the correct group and stage labels](https://about.gitlab.com/handbook/engineering/quality/triage-operations/#auto-labelling-of-issues).
+
+If you are an expert in a particular area, it makes it easier to find issues to
+work on. You can also subscribe to those labels to receive an email each time an
+issue is labeled with a feature label corresponding to your expertise.
+
+Examples of feature labels are ~wiki, ~ldap, ~api, ~issues, ~"merge requests" etc.
+
+#### Naming and color convention
-## Department labels
+Feature labels are all-lowercase.
+
+### Department labels
The current department labels are:
- ~UX
- ~Quality
-## Specialization labels
+### Team labels
+
+**Important**: Most of the historical team labels (e.g. Manage, Plan etc.) are
+now deprecated in favor of [Group labels](#group-labels) and [Stage labels](#stage-labels).
+
+Team labels specify what team is responsible for this issue.
+Assigning a team label makes sure issues get the attention of the appropriate
+people.
+
+The current team labels are:
+
+- ~Delivery
+- ~Documentation
+
+#### Naming and color convention
+
+Team labels are always capitalized so that they show up as the first label for
+any issue.
+
+### Specialization labels
These labels narrow the [specialization](https://about.gitlab.com/company/team/structure/#specialist) on a unit of work.
- ~frontend
- ~backend
-## Release Scoping labels
+### Release scoping labels
Release Scoping labels help us clearly communicate expectations of the work for the
release. There are three levels of Release Scoping labels:
@@ -145,7 +260,7 @@ Each issue scheduled for the current milestone should be labeled ~Deliverable
or ~"Stretch". Any open issue for a previous milestone should be labeled
~"Next Patch Release", or otherwise rescheduled to a different milestone.
-### Priority labels
+#### Priority labels
Priority labels help us define the time a ~bug fix should be completed. Priority determines how quickly the defect turnaround time must be.
If there are multiple defects, the priority decides which defect has to be fixed immediately versus later.
@@ -158,7 +273,7 @@ This label documents the planned timeline & urgency which is used to measure aga
| ~P3 | Medium Priority | Within the next 3 releases (approx one quarter or 90 days) |
| ~P4 | Low Priority | Anything outside the next 3 releases (more than one quarter or 120 days) |
-## Severity labels
+### Severity labels
Severity labels help us clearly communicate the impact of a ~bug on users.
There can be multiple facets of the impact. The below is a guideline.
@@ -187,7 +302,7 @@ If a bug seems to fall between two severity labels, assign it to the higher-seve
- Label colors are incorrect.
- UI elements are not fully aligned.
-## Label for community contributors
+### Label for community contributors
Issues that are beneficial to our users, 'nice to haves', that we currently do
not have the capacity for or want to give the priority to, are labeled as
@@ -217,11 +332,11 @@ After adding the ~"Accepting merge requests" label, we try to estimate the
[weight](#issue-weight) of the issue. We use issue weight to let contributors
know how difficult the issue is. Additionally:
-- We advertise [`Accepting merge requests` issues with weight < 5][up-for-grabs]
+- We advertise [`Accepting merge requests` issues with weight < 5](https://gitlab.com/groups/gitlab-org/-/issues?state=opened&label_name[]=Accepting+merge+requests&assignee_id=None&sort=weight)
as suitable for people that have never contributed to GitLab before on the
[Up For Grabs campaign](http://up-for-grabs.net)
- We encourage people that have never contributed to any open source project to
- look for [`Accepting merge requests` issues with a weight of 1][first-timers]
+ look for [`Accepting merge requests` issues with a weight of 1](https://gitlab.com/groups/gitlab-org/-/issues?state=opened&label_name[]=Accepting+merge+requests&assignee_id=None&sort=weight&weight=1)
If you've decided that you would like to work on an issue, please @-mention
the [appropriate product manager](https://about.gitlab.com/handbook/product/#who-to-talk-to-for-what)
@@ -234,42 +349,29 @@ GitLab team members who apply the ~"Accepting merge requests" label to an issue
should update the issue description with a responsible product manager, inviting
any potential community contributor to @-mention per above.
-[up-for-grabs]: https://gitlab.com/groups/gitlab-org/-/issues?state=opened&label_name[]=Accepting+merge+requests&assignee_id=None&sort=weight
-[first-timers]: https://gitlab.com/groups/gitlab-org/-/issues?state=opened&label_name[]=Accepting+merge+requests&assignee_id=None&sort=weight&weight=1
-
-## Issue triaging
-
-Our issue triage policies are [described in our handbook]. You are very welcome
-to help the GitLab team triage issues. We also organize [issue bash events] once
-every quarter.
+### Stewardship label
-The most important thing is making sure valid issues receive feedback from the
-development team. Therefore the priority is mentioning developers that can help
-on those issues. Please select someone with relevant experience from the
-[GitLab team][team]. If there is nobody mentioned with that expertise look in
-the commit history for the affected files to find someone.
+For issues related to the open source stewardship of GitLab,
+there is the ~"stewardship" label.
-We also use [GitLab Triage] to automate some triaging policies. This is
-currently set up as a [scheduled pipeline] running on [quality/triage-ops]
-project.
+This label is to be used for issues in which the stewardship of GitLab
+is a topic of discussion. For instance if GitLab Inc. is planning to add
+features from GitLab EE to GitLab CE, related issues would be labelled with
+~"stewardship".
-[described in our handbook]: https://about.gitlab.com/handbook/engineering/issue-triage/
-[issue bash events]: https://gitlab.com/gitlab-org/gitlab-ce/issues/17815
-[GitLab Triage]: https://gitlab.com/gitlab-org/gitlab-triage
-[scheduled pipeline]: https://gitlab.com/gitlab-org/quality/triage-ops/pipeline_schedules/10512/edit
-[quality/triage-ops]: https://gitlab.com/gitlab-org/quality/triage-ops
-[team]: https://about.gitlab.com/team/
+A recent example of this was the issue for
+[bringing the time tracking API to GitLab CE](https://gitlab.com/gitlab-org/gitlab-ce/issues/25517#note_20019084).
## Feature proposals
To create a feature proposal for CE, open an issue on the
-[issue tracker of CE][ce-tracker].
+[issue tracker of CE](https://gitlab.com/gitlab-org/gitlab-ce/issues).
For feature proposals for EE, open an issue on the
-[issue tracker of EE][ee-tracker].
+[issue tracker of EE](https://gitlab.com/gitlab-org/gitlab-ee/issues).
In order to help track the feature proposals, we have created a
-[`feature`][fl] label. For the time being, users that are not members
+[`feature`](https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=feature) label. For the time being, users that are not members
of the project cannot add labels. You can instead ask one of the [core team](https://about.gitlab.com/community/core-team/)
members to add the label ~feature to the issue or add the following
code snippet right after your description in a new line: `~feature`.
@@ -286,20 +388,6 @@ need to ask one of the [core team](https://about.gitlab.com/community/core-team/
If you want to create something yourself, consider opening an issue first to
discuss whether it is interesting to include this in GitLab.
-[fl]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=feature
-
-## Issue tracker guidelines
-
-**[Search the issue tracker][ce-tracker]** for similar entries before
-submitting your own, there's a good chance somebody else had the same issue or
-feature proposal. Show your support with an award emoji and/or join the
-discussion.
-
-Please submit bugs using the ['Bug' issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Bug.md) provided on the issue tracker.
-The text in the parenthesis is there to help you with what to include. Omit it
-when submitting the actual issue. You can copy-paste it and then edit as you
-see fit.
-
## Issue weight
Issue weight allows us to get an idea of the amount of work required to solve
@@ -345,7 +433,7 @@ addressed.
## Technical and UX debt
In order to track things that can be improved in GitLab's codebase,
-we use the ~"technical debt" label in [GitLab's issue tracker][ce-tracker].
+we use the ~"technical debt" label in [GitLab's issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues).
For missed user experience requirements, we use the ~"UX debt" label.
These labels should be added to issues that describe things that can be improved,
@@ -406,25 +494,6 @@ should be of the same quality as those created
**must not** begin with `Follow-up`! The creating maintainer should also expect
to be involved in some capacity when work begins on the follow-up issue.
-## Stewardship
-
-For issues related to the open source stewardship of GitLab,
-there is the ~"stewardship" label.
-
-This label is to be used for issues in which the stewardship of GitLab
-is a topic of discussion. For instance if GitLab Inc. is planning to add
-features from GitLab EE to GitLab CE, related issues would be labelled with
-~"stewardship".
-
-A recent example of this was the issue for
-[bringing the time tracking API to GitLab CE][time-tracking-issue].
-
-[time-tracking-issue]: https://gitlab.com/gitlab-org/gitlab-ce/issues/25517#note_20019084
-
---
[Return to Contributing documentation](index.md)
-
-[ce-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/issues
-[ee-tracker]: https://gitlab.com/gitlab-org/gitlab-ee/issues
-[inferred-labels]: https://gitlab.com/gitlab-org/quality/triage-ops/merge_requests/155
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index 4e9c5c81379..bdb026d498d 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -1,4 +1,4 @@
-# Merge requests
+# Merge requests workflow
We welcome merge requests from everyone, with fixes and improvements
to GitLab code, tests, and documentation. The issues that are specifically suitable
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index c1e3eb9680b..283e8bea8d5 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -506,15 +506,6 @@ Example:
For more information, see the [confidential issue](../../user/project/issues/confidential_issues.md) `https://gitlab.com/gitlab-org/gitlab-ce/issues/<issue_number>`.
```
-### Unlinking emails
-
-By default, all email addresses will render in an email tag on docs.gitlab.com.
-To escape the code block and unlink email addresses, use two backticks:
-
-```md
-`` example@email.com ``
-```
-
## Navigation
To indicate the steps of navigation through the UI:
@@ -783,8 +774,6 @@ For multiple paragraphs, use the symbol `>` before every line:
>
> - This is a list item
> - Second item in the list
->
-> ### This is an `h3`
```
Which renders to:
@@ -795,9 +784,6 @@ Which renders to:
>
> - This is a list item
> - Second item in the list
->
-> ### This is an `h3`
->{:.no_toc}
## Terms
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 1358851f3cd..391361a4b8f 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -1047,8 +1047,6 @@ code base. Examples of backports include the following:
Here is a workflow to make sure those changes end up backported safely into CE too.
-(This approach does not refer to changes introduced via [csslab](https://gitlab.com/gitlab-org/csslab/).)
-
1. **Make your changes in the EE branch.** If possible, keep a separated commit (to be squashed) to help backporting and review.
1. **Open merge request to EE project.**
1. **Apply the changes you made to CE files in a branch of the CE project.** (Tip: Use `patch` with the diff from your commit in EE branch)
diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md
index 676bce32998..3a8ea04407f 100644
--- a/doc/development/fe_guide/performance.md
+++ b/doc/development/fe_guide/performance.md
@@ -81,7 +81,7 @@ bundle and included on the page.
> can find this out by inspecting `document.body.dataset.page` within your
> browser's developer console while on any page within gitlab.
-#### Important Considerations:
+#### Important Considerations
- **Keep Entry Points Lite:**
Page-specific javascript entry points should be as lite as possible. These
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index 83444093f9c..2df0e846671 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -94,7 +94,7 @@ become available, you will be able to share job templates like this
Dependencies should be kept to the minimum. The introduction of a new
dependency should be argued in the merge request, as per our [Approval
Guidelines](../code_review.md#approval-guidelines). Both [License
-Management](../../user/project/merge_requests/license_management.md)
+Management](../../user/application_security/license_compliance/index.md)
**(ULTIMATE)** and [Dependency
Scanning](../../user/application_security/dependency_scanning/index.md)
**(ULTIMATE)** should be activated on all projects to ensure new dependencies
diff --git a/doc/development/i18n/translation.md b/doc/development/i18n/translation.md
index 62be3786549..15b1af1aa8f 100644
--- a/doc/development/i18n/translation.md
+++ b/doc/development/i18n/translation.md
@@ -92,4 +92,3 @@ To propose additions to the glossary please
In French, the "écriture inclusive" is now over (see on [Legifrance](https://www.legifrance.gouv.fr/affichTexte.do?cidTexte=JORFTEXT000036068906&categorieLien=id)).
So, to include both genders, write “Utilisateurs et utilisatrices” instead of “Utilisateur·rice·s”.
When space is missing, the male gender should be used alone.
-
diff --git a/doc/development/new_fe_guide/dependencies.md b/doc/development/new_fe_guide/dependencies.md
index 8a6930acd37..161ffb1fb57 100644
--- a/doc/development/new_fe_guide/dependencies.md
+++ b/doc/development/new_fe_guide/dependencies.md
@@ -1,6 +1,6 @@
# Dependencies
-## Adding Dependencies.
+## Adding Dependencies
GitLab uses `yarn` to manage dependencies. These dependencies are defined in
two groups within `package.json`, `dependencies` and `devDependencies`. For
diff --git a/doc/development/new_fe_guide/development/testing.md b/doc/development/new_fe_guide/development/testing.md
index e0d413b748b..b990425ca3c 100644
--- a/doc/development/new_fe_guide/development/testing.md
+++ b/doc/development/new_fe_guide/development/testing.md
@@ -3,4 +3,3 @@ redirect_to: '../../testing_guide/frontend_testing.md'
---
This document was moved to [another location](../../testing_guide/frontend_testing.md).
-
diff --git a/doc/development/testing_guide/end_to_end/quick_start_guide.md b/doc/development/testing_guide/end_to_end/quick_start_guide.md
index e1df8be8b6f..d52d6db38b9 100644
--- a/doc/development/testing_guide/end_to_end/quick_start_guide.md
+++ b/doc/development/testing_guide/end_to_end/quick_start_guide.md
@@ -10,7 +10,7 @@ It's important to understand that end-to-end tests of isolated features, such as
If you don't exactly understand what we mean by **not everything needs to happen through the GUI,** please make sure you've read the [best practices](best_practices.md) before moving on.
-## This document covers the following items:
+## This document covers the following items
- [0.](#0-are-end-to-end-tests-needed) Identifying if end-to-end tests are really needed
- [1.](#1-identifying-the-devops-stage) Identifying the [DevOps stage](https://about.gitlab.com/stages-devops-lifecycle/) of the feature that you are going to cover with end-to-end tests
diff --git a/doc/development/testing_guide/end_to_end/style_guide.md b/doc/development/testing_guide/end_to_end/style_guide.md
index 97560e616a1..54ed3f34c89 100644
--- a/doc/development/testing_guide/end_to_end/style_guide.md
+++ b/doc/development/testing_guide/end_to_end/style_guide.md
@@ -141,4 +141,4 @@ Resource::MergeRequest.fabricate! do |merge_request_page|
end
```
-> Besides the advantage of having a standard in place, by following this standard we also write shorter lines of code. \ No newline at end of file
+> Besides the advantage of having a standard in place, by following this standard we also write shorter lines of code.
diff --git a/doc/development/testing_guide/index.md b/doc/development/testing_guide/index.md
index 96e8c30a679..173471e3af8 100644
--- a/doc/development/testing_guide/index.md
+++ b/doc/development/testing_guide/index.md
@@ -13,7 +13,7 @@ importance.
GitLab is built on top of [Ruby on Rails](https://rubyonrails.org/), and we're using [RSpec] for all
the backend tests, with [Capybara] for end-to-end integration testing.
-On the frontend side, we're using [Karma] and [Jasmine] for JavaScript unit and
+On the frontend side, we're using [Jest](https://jestjs.io/) and [Karma](http://karma-runner.github.io/)/[Jasmine](https://jasmine.github.io/) for JavaScript unit and
integration testing.
Following are two great articles that everyone should read to understand what
@@ -64,6 +64,4 @@ Everything you should know about how to run end-to-end tests using
[RSpec]: https://github.com/rspec/rspec-rails#feature-specs
[Capybara]: https://github.com/teamcapybara/capybara
-[Karma]: http://karma-runner.github.io/
-[Jasmine]: https://jasmine.github.io/
[gitlab-qa]: https://gitlab.com/gitlab-org/gitlab-qa
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
index 11449712a04..28a60660995 100644
--- a/doc/development/testing_guide/review_apps.md
+++ b/doc/development/testing_guide/review_apps.md
@@ -132,7 +132,7 @@ to prevent other pods from being scheduled on this node pool.
This is to ensure Tiller isn't affected by "noisy" neighbors that could put
their node under pressure.
-## How to:
+## How to
### Log into my Review App
diff --git a/doc/development/testing_guide/testing_levels.md b/doc/development/testing_guide/testing_levels.md
index 0090c84cbf0..1aee306f492 100644
--- a/doc/development/testing_guide/testing_levels.md
+++ b/doc/development/testing_guide/testing_levels.md
@@ -126,7 +126,7 @@ possible).
| ---------- | -------------- | ----- |
| `spec/features/` | [Capybara] + [RSpec] | If your test has the `:js` metadata, the browser driver will be [Poltergeist], otherwise it's using [RackTest]. |
-### Consider **not** writing a system test!
+### Consider **not** writing a system test
If we're confident that the low-level components work well (and we should be if
we have enough Unit & Integration tests), we shouldn't need to duplicate their
diff --git a/doc/development/ux_guide/animation.md b/doc/development/ux_guide/animation.md
index a998ab74a96..0f7a24042bb 100644
--- a/doc/development/ux_guide/animation.md
+++ b/doc/development/ux_guide/animation.md
@@ -1,5 +1,5 @@
---
-redirect_to: 'https://design.gitlab.com/product-foundations/motion'
+redirect_to: 'https://design.gitlab.com/product-foundations/motion/'
---
-The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/product-foundations/motion).
+The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/product-foundations/motion/).
diff --git a/doc/development/ux_guide/illustrations.md b/doc/development/ux_guide/illustrations.md
index 3592d25c95d..815f870f8c5 100644
--- a/doc/development/ux_guide/illustrations.md
+++ b/doc/development/ux_guide/illustrations.md
@@ -1,5 +1,5 @@
---
-redirect_to: 'https://design.gitlab.com/product-foundations/illustration'
+redirect_to: 'https://design.gitlab.com/product-foundations/illustration/'
---
-The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/product-foundations/illustration).
+The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/product-foundations/illustration/).
diff --git a/doc/gitlab-basics/add-merge-request.md b/doc/gitlab-basics/add-merge-request.md
index 1a6a26152fa..28f32fefb95 100644
--- a/doc/gitlab-basics/add-merge-request.md
+++ b/doc/gitlab-basics/add-merge-request.md
@@ -12,8 +12,6 @@ check the [merge requests documentation](../user/project/merge_requests/index.md
you can watch our [GitLab Flow video](https://www.youtube.com/watch?v=InKNIvky2KE) for
a quick overview of working with merge requests.
----
-
1. Before you start, you should have already [created a branch](create-branch.md)
and [pushed your changes](start-using-git.md#send-changes-to-gitlabcom) to GitLab.
1. Go to the project where you'd like to merge your changes and click on the
diff --git a/doc/gitlab-basics/create-project.md b/doc/gitlab-basics/create-project.md
index 8bbaf5d1927..18565daa900 100644
--- a/doc/gitlab-basics/create-project.md
+++ b/doc/gitlab-basics/create-project.md
@@ -2,7 +2,7 @@
type: howto
---
-# Creating projects
+# Create a project
Most work in GitLab is done within a [Project](../user/project/index.md). Files and
code are saved in projects, and most features are used within the scope of projects.
diff --git a/doc/gitlab-basics/create-your-ssh-keys.md b/doc/gitlab-basics/create-your-ssh-keys.md
index 338b96374aa..98f2679c9d6 100644
--- a/doc/gitlab-basics/create-your-ssh-keys.md
+++ b/doc/gitlab-basics/create-your-ssh-keys.md
@@ -5,7 +5,7 @@ type: howto
# Create and add your SSH public key
It is best practice to use [Git over SSH instead of Git over HTTP](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols).
-In order to use SSH, you will need to
+In order to use SSH, you will need to:
1. [Create an SSH key pair](#creating-your-ssh-key-pair) on your local computer.
1. [Add the key to GitLab](#adding-your-ssh-public-key-to-gitlab).
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 2989a4edaf7..6039ddc45ae 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -611,7 +611,7 @@ You can specify a different Git repository by providing it as an extra parameter
sudo -u git -H bundle exec rake "gitlab:gitaly:install[/home/git/gitaly,/home/git/repositories,https://example.com/gitaly.git]" RAILS_ENV=production
```
-Next, make sure gitaly configured:
+Next, make sure that Gitaly is configured:
```sh
# Restrict Gitaly socket access
diff --git a/doc/security/rack_attack.md b/doc/security/rack_attack.md
index b99bfb16829..09d29bf3446 100644
--- a/doc/security/rack_attack.md
+++ b/doc/security/rack_attack.md
@@ -77,9 +77,12 @@ authentication requests were received in a 3-minute period from a single IP addr
This applies only to Git requests and container registry (`/jwt/auth`) requests
(combined).
-This limit is reset by requests that authenticate successfully. For example, 29
-failed authentication requests followed by 1 successful request, followed by 29
-more failed authentication requests would not trigger a ban.
+This limit:
+
+- Is reset by requests that authenticate successfully. For example, 29
+ failed authentication requests followed by 1 successful request, followed by 29
+ more failed authentication requests would not trigger a ban.
+- Does not apply to JWT requests authenticated by `gitlab-ci-token`.
No response headers are provided.
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 6021e8cff1d..19d8a6b5e2b 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -414,7 +414,7 @@ report is created, it's uploaded as an artifact which you can later download and
check out.
Any licenses are also shown in the merge request widget. Read more how
-[License Compliance works](../../user/application_security/license_management/index.md).
+[License Compliance works](../../user/application_security/license_compliance/index.md).
### Auto Container Scanning **(ULTIMATE)**
diff --git a/doc/user/admin_area/settings/terms.md b/doc/user/admin_area/settings/terms.md
index baf219ac9c7..0b5f9a13b03 100644
--- a/doc/user/admin_area/settings/terms.md
+++ b/doc/user/admin_area/settings/terms.md
@@ -4,8 +4,7 @@ type: reference
# Enforce accepting Terms of Service **(CORE ONLY)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18570)
-> in [GitLab Core](https://about.gitlab.com/pricing/) 10.8
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18570) in [GitLab Core](https://about.gitlab.com/pricing/) 10.8.
An admin can enforce acceptance of a terms of service and privacy policy. When this option is enabled, new and existing users must accept the terms.
diff --git a/doc/user/admin_area/settings/third_party_offers.md b/doc/user/admin_area/settings/third_party_offers.md
index ca26147b287..50dea8f50a2 100644
--- a/doc/user/admin_area/settings/third_party_offers.md
+++ b/doc/user/admin_area/settings/third_party_offers.md
@@ -4,8 +4,7 @@ type: reference
# Third party offers **(CORE ONLY)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20379)
-> in [GitLab Core](https://about.gitlab.com/pricing/) 11.1
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20379) in [GitLab Core](https://about.gitlab.com/pricing/) 11.1.
Within GitLab, we inform users of available third-party offers they might find valuable in order
to enhance the development of their projects. An example is the Google Cloud Platform free credit
diff --git a/doc/user/application_security/license_management/img/license_management.png b/doc/user/application_security/license_compliance/img/license_compliance.png
index cdce6b5fe38..cdce6b5fe38 100644
--- a/doc/user/application_security/license_management/img/license_management.png
+++ b/doc/user/application_security/license_compliance/img/license_compliance.png
Binary files differ
diff --git a/doc/user/application_security/license_management/img/license_management_add_license.png b/doc/user/application_security/license_compliance/img/license_compliance_add_license.png
index c9a5dc14c57..c9a5dc14c57 100644
--- a/doc/user/application_security/license_management/img/license_management_add_license.png
+++ b/doc/user/application_security/license_compliance/img/license_compliance_add_license.png
Binary files differ
diff --git a/doc/user/application_security/license_management/img/license_management_decision.png b/doc/user/application_security/license_compliance/img/license_compliance_decision.png
index fbf90bec7fd..fbf90bec7fd 100644
--- a/doc/user/application_security/license_management/img/license_management_decision.png
+++ b/doc/user/application_security/license_compliance/img/license_compliance_decision.png
Binary files differ
diff --git a/doc/user/application_security/license_management/img/license_management_pipeline_tab.png b/doc/user/application_security/license_compliance/img/license_compliance_pipeline_tab.png
index 80ffca815b9..80ffca815b9 100644
--- a/doc/user/application_security/license_management/img/license_management_pipeline_tab.png
+++ b/doc/user/application_security/license_compliance/img/license_compliance_pipeline_tab.png
Binary files differ
diff --git a/doc/user/application_security/license_management/img/license_management_search.png b/doc/user/application_security/license_compliance/img/license_compliance_search.png
index b3ffd8d95a1..b3ffd8d95a1 100644
--- a/doc/user/application_security/license_management/img/license_management_search.png
+++ b/doc/user/application_security/license_compliance/img/license_compliance_search.png
Binary files differ
diff --git a/doc/user/application_security/license_management/img/license_management_settings.png b/doc/user/application_security/license_compliance/img/license_compliance_settings.png
index 2e3e8888e93..2e3e8888e93 100644
--- a/doc/user/application_security/license_management/img/license_management_settings.png
+++ b/doc/user/application_security/license_compliance/img/license_compliance_settings.png
Binary files differ
diff --git a/doc/user/application_security/license_compliance/index.md b/doc/user/application_security/license_compliance/index.md
new file mode 100644
index 00000000000..f74b958cf67
--- /dev/null
+++ b/doc/user/application_security/license_compliance/index.md
@@ -0,0 +1,243 @@
+---
+type: reference, howto
+---
+
+# License Compliance **(ULTIMATE)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5483) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0.
+
+## Overview
+
+If you are using [GitLab CI/CD](../../../ci/README.md), you can search your project dependencies for their licenses
+using License Compliance.
+
+You can take advantage of License Compliance by either [including the job](#configuration)
+in your existing `.gitlab-ci.yml` file or by implicitly using
+[Auto License Compliance](../../../topics/autodevops/index.md#auto-license-compliance-ultimate)
+that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
+
+GitLab checks the License Compliance report, compares the licenses between the
+source and target branches, and shows the information right on the merge request.
+Blacklisted licenses will be clearly visible with an `x` red icon next to them
+as well as new licenses which need a decision from you. In addition, you can
+[manually approve or blacklist](#project-policies-for-license-compliance)
+licenses in your project's settings.
+
+NOTE: **Note:**
+If the license compliance report doesn't have anything to compare to, no information
+will be displayed in the merge request area. That is the case when you add the
+`license_management` job in your `.gitlab-ci.yml` for the first time.
+Consecutive merge requests will have something to compare to and the license
+compliance report will be shown properly.
+
+![License Compliance Widget](img/license_compliance.png)
+
+If you are a project or group Maintainer, you can click on a license to be given
+the choice to approve it or blacklist it.
+
+![License approval decision](img/license_compliance_decision.png)
+
+## Use cases
+
+It helps you find what licenses your project uses in its dependencies, and decide for each of then
+whether to allow it or forbid it. For example, your application is using an external (open source)
+library whose license is incompatible with yours.
+
+## Supported languages and package managers
+
+The following languages and package managers are supported.
+
+| Language | Package managers | Scan Tool |
+|------------|-------------------------------------------------------------------|----------------------------------------------------------|
+| JavaScript | [Bower](https://bower.io/), [npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Go | [Godep](https://github.com/tools/godep), go get ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), gvt ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), glide ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), dep ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), trash ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) and govendor ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), [go mod](https://github.com/golang/go/wiki/Modules) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Java | [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| .NET | [Nuget](https://www.nuget.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Python | [pip](https://pip.pypa.io/en/stable/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Ruby | [gem](https://rubygems.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Erlang | [rebar](https://www.rebar3.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Objective-C, Swift | [Carthage](https://github.com/Carthage/Carthage) , [CocoaPods v0.39 and below](https://cocoapods.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Elixir | [mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| C++/C | [conan](https://conan.io/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Scala | [sbt](https://www.scala-sbt.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Rust | [cargo](https://crates.io/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
+| PHP | [composer](https://getcomposer.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
+
+## Requirements
+
+To run a License Compliance scanning job, you need GitLab Runner with the
+[`docker` executor](https://docs.gitlab.com/runner/executors/docker.html).
+
+## Configuration
+
+For GitLab 11.9 and later, to enable License Compliance, you must
+[include](../../../ci/yaml/README.md#includetemplate) the
+[`License-Management.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/License-Management.gitlab-ci.yml)
+that's provided as a part of your GitLab installation.
+For GitLab versions earlier than 11.9, you can copy and use the job as defined
+that template.
+
+Add the following to your `.gitlab-ci.yml` file:
+
+```yaml
+include:
+ template: License-Management.gitlab-ci.yml
+```
+
+The included template will create a `license_management` job in your CI/CD pipeline
+and scan your dependencies to find their licenses.
+
+The results will be saved as a
+[License Compliance report artifact](../../../ci/yaml/README.md#artifactsreportslicense_management-ultimate)
+that you can later download and analyze. Due to implementation limitations, we
+always take the latest License Compliance artifact available. Behind the scenes, the
+[GitLab License Compliance Docker image](https://gitlab.com/gitlab-org/security-products/license-management)
+is used to detect the languages/frameworks and in turn analyzes the licenses.
+
+The License Compliance settings can be changed through environment variables by using the
+[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`. These variables are documented in the [License Compliance documentation](https://gitlab.com/gitlab-org/security-products/license-management#settings).
+
+### Installing custom dependencies
+
+> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.4.
+
+The `license_management` image already embeds many auto-detection scripts, languages,
+and packages. Nevertheless, it's almost impossible to cover all cases for all projects.
+That's why sometimes it's necessary to install extra packages, or to have extra steps
+in the project automated setup, like the download and installation of a certificate.
+For that, a `LICENSE_MANAGEMENT_SETUP_CMD` environment variable can be passed to the container,
+with the required commands to run before the license detection.
+
+If present, this variable will override the setup step necessary to install all the packages
+of your application (e.g.: for a project with a `Gemfile`, the setup step could be
+`bundle install`).
+
+For example:
+
+```yaml
+include:
+ template: License-Management.gitlab-ci.yml
+
+variables:
+ LICENSE_MANAGEMENT_SETUP_CMD: sh my-custom-install-script.sh
+```
+
+In this example, `my-custom-install-script.sh` is a shell script at the root
+directory of your project.
+
+### Overriding the template
+
+If you want to override the job definition (for example, change properties like
+`variables` or `dependencies`), you need to declare a `license_management` job
+after the template inclusion and specify any additional keys under it. For example:
+
+```yaml
+include:
+ template: License-Management.gitlab-ci.yml
+
+license_management:
+ variables:
+ CI_DEBUG_TRACE: "true"
+```
+
+### Configuring Maven projects
+
+The License Compliance tool provides a `MAVEN_CLI_OPTS` environment variable which can hold
+the command line arguments to pass to the `mvn install` command which is executed under the hood.
+Feel free to use it for the customization of Maven execution. For example:
+
+```yaml
+include:
+ template: License-Management.gitlab-ci.yml
+
+license_management:
+ variables:
+ MAVEN_CLI_OPTS: --debug
+```
+
+`mvn install` runs through all of the [build life cycle](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
+stages prior to `install`, including `test`. Running unit tests is not directly
+necessary for the license scanning purposes and consumes time, so it's skipped
+by having the default value of `MAVEN_CLI_OPTS` as `-DskipTests`. If you want
+to supply custom `MAVEN_CLI_OPTS` and skip tests at the same time, don't forget
+to explicitly add `-DskipTests` to your options.
+If you still need to run tests during `mvn install`, add `-DskipTests=false` to
+`MAVEN_CLI_OPTS`.
+
+### Selecting the version of Python
+
+> - [Introduced](https://gitlab.com/gitlab-org/security-products/license-management/merge_requests/36) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
+> - In GitLab 12.2, Python 3.5 became the default.
+
+License Compliance uses Python 3.5 and pip 19.1 by default.
+If your project requires Python 2, you can switch to Python 2.7 and pip 10.0
+by setting the `LM_PYTHON_VERSION` environment variable to `2`.
+
+```yaml
+include:
+ template: License-Management.gitlab-ci.yml
+
+license_management:
+ variables:
+ LM_PYTHON_VERSION: 2
+```
+
+## Project policies for License Compliance
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5940) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.4.
+
+From the project's settings:
+
+- The list of licenses and their status can be managed.
+- Licenses can be manually approved or blacklisted.
+
+To approve or blacklist a license:
+
+1. Either use the **Manage licenses** button in the merge request widget, or
+ navigate to the project's **Settings > CI/CD** and expand the
+ **License Compliance** section.
+1. Click the **Add a license** button.
+
+ ![License Compliance Add License](img/license_compliance_add_license.png)
+
+1. In the **License name** dropdown, either:
+ - Select one of the available licenses. You can search for licenses in the field
+ at the top of the list.
+ - Enter arbitrary text in the field at the top of the list. This will cause the text to be
+ added as a license name to the list.
+1. Select the **Approve** or **Blacklist** radio button to approve or blacklist respectively
+ the selected license.
+
+To modify an existing license:
+
+1. In the **License Compliance** list, click the **Approved/Declined** dropdown to change it to the desired status.
+
+ ![License Compliance Settings](img/license_compliance_settings.png)
+
+Searching for Licenses:
+
+1. Use the **Search** box to search for a specific license.
+
+ ![License Compliance Search](img/license_compliance_search.png)
+
+## License Compliance report under pipelines
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5491) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.2.
+
+From your project's left sidebar, navigate to **CI/CD > Pipelines** and click on the
+pipeline ID that has a `license_management` job to see the Licenses tab with the listed
+licenses (if any).
+
+![License Compliance Pipeline Tab](img/license_compliance_pipeline_tab.png)
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/user/application_security/license_management/index.md b/doc/user/application_security/license_management/index.md
index 44b2671930e..319da2c3a6e 100644
--- a/doc/user/application_security/license_management/index.md
+++ b/doc/user/application_security/license_management/index.md
@@ -1,245 +1,5 @@
---
-type: reference, howto
+redirect_to: ../license_compliance/index.md
---
-# License Compliance **(ULTIMATE)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5483)
-in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0.
-
-## Overview
-
-If you are using [GitLab CI/CD](../../../ci/README.md), you can search your project dependencies for their licenses
-using License Compliance.
-
-You can take advantage of License Compliance by either [including the job](#configuration)
-in your existing `.gitlab-ci.yml` file or by implicitly using
-[Auto License Compliance](../../../topics/autodevops/index.md#auto-license-compliance-ultimate)
-that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
-
-GitLab checks the License Compliance report, compares the licenses between the
-source and target branches, and shows the information right on the merge request.
-Blacklisted licenses will be clearly visible with an `x` red icon next to them
-as well as new licenses which need a decision from you. In addition, you can
-[manually approve or blacklist](#project-policies-for-license-compliance)
-licenses in your project's settings.
-
-NOTE: **Note:**
-If the license management report doesn't have anything to compare to, no information
-will be displayed in the merge request area. That is the case when you add the
-`license_management` job in your `.gitlab-ci.yml` for the first time.
-Consecutive merge requests will have something to compare to and the license
-management report will be shown properly.
-
-![License Compliance Widget](img/license_management.png)
-
-If you are a project or group Maintainer, you can click on a license to be given
-the choice to approve it or blacklist it.
-
-![License approval decision](img/license_management_decision.png)
-
-## Use cases
-
-It helps you find what licenses your project uses in its dependencies, and decide for each of then
-whether to allow it or forbid it. For example, your application is using an external (open source)
-library whose license is incompatible with yours.
-
-## Supported languages and package managers
-
-The following languages and package managers are supported.
-
-| Language | Package managers | Scan Tool |
-|------------|-------------------------------------------------------------------|----------------------------------------------------------|
-| JavaScript | [Bower](https://bower.io/), [npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Go | [Godep](https://github.com/tools/godep), go get ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), gvt ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), glide ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), dep ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), trash ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) and govendor ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), [go mod](https://github.com/golang/go/wiki/Modules) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Java | [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
-| .NET | [Nuget](https://www.nuget.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Python | [pip](https://pip.pypa.io/en/stable/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Ruby | [gem](https://rubygems.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Erlang | [rebar](https://www.rebar3.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Objective-C, Swift | [Carthage](https://github.com/Carthage/Carthage) , [CocoaPods v0.39 and below](https://cocoapods.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Elixir | [mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
-| C++/C | [conan](https://conan.io/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Scala | [sbt](https://www.scala-sbt.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Rust | [cargo](https://crates.io/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
-| PHP | [composer](https://getcomposer.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
-
-## Requirements
-
-To run a License Compliance scanning job, you need GitLab Runner with the
-[`docker` executor](https://docs.gitlab.com/runner/executors/docker.html).
-
-## Configuration
-
-For GitLab 11.9 and later, to enable License Compliance, you must
-[include](../../../ci/yaml/README.md#includetemplate) the
-[`License-Management.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/ci/templates/Security/License-Management.gitlab-ci.yml)
-that's provided as a part of your GitLab installation.
-For GitLab versions earlier than 11.9, you can copy and use the job as defined
-that template.
-
-Add the following to your `.gitlab-ci.yml` file:
-
-```yaml
-include:
- template: License-Management.gitlab-ci.yml
-```
-
-The included template will create a `license_management` job in your CI/CD pipeline
-and scan your dependencies to find their licenses.
-
-The results will be saved as a
-[License Compliance report artifact](../../../ci/yaml/README.md#artifactsreportslicense_management-ultimate)
-that you can later download and analyze. Due to implementation limitations, we
-always take the latest License Compliance artifact available. Behind the scenes, the
-[GitLab License Compliance Docker image](https://gitlab.com/gitlab-org/security-products/license-management)
-is used to detect the languages/frameworks and in turn analyzes the licenses.
-
-The License Compliance settings can be changed through environment variables by using the
-[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`. These variables are documented in the [License Compliance documentation](https://gitlab.com/gitlab-org/security-products/license-management#settings).
-
-### Installing custom dependencies
-
-> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.4.
-
-The `license_management` image already embeds many auto-detection scripts, languages,
-and packages. Nevertheless, it's almost impossible to cover all cases for all projects.
-That's why sometimes it's necessary to install extra packages, or to have extra steps
-in the project automated setup, like the download and installation of a certificate.
-For that, a `LICENSE_MANAGEMENT_SETUP_CMD` environment variable can be passed to the container,
-with the required commands to run before the license detection.
-
-If present, this variable will override the setup step necessary to install all the packages
-of your application (e.g.: for a project with a `Gemfile`, the setup step could be
-`bundle install`).
-
-For example:
-
-```yaml
-include:
- template: License-Management.gitlab-ci.yml
-
-variables:
- LICENSE_MANAGEMENT_SETUP_CMD: sh my-custom-install-script.sh
-```
-
-In this example, `my-custom-install-script.sh` is a shell script at the root
-directory of your project.
-
-### Overriding the template
-
-If you want to override the job definition (for example, change properties like
-`variables` or `dependencies`), you need to declare a `license_management` job
-after the template inclusion and specify any additional keys under it. For example:
-
-```yaml
-include:
- template: License-Management.gitlab-ci.yml
-
-license_management:
- variables:
- CI_DEBUG_TRACE: "true"
-```
-
-### Configuring Maven projects
-
-The License Compliance tool provides a `MAVEN_CLI_OPTS` environment variable which can hold
-the command line arguments to pass to the `mvn install` command which is executed under the hood.
-Feel free to use it for the customization of Maven execution. For example:
-
-```yaml
-include:
- template: License-Management.gitlab-ci.yml
-
-license_management:
- variables:
- MAVEN_CLI_OPTS: --debug
-```
-
-`mvn install` runs through all of the [build life cycle](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
-stages prior to `install`, including `test`. Running unit tests is not directly
-necessary for the license scanning purposes and consumes time, so it's skipped
-by having the default value of `MAVEN_CLI_OPTS` as `-DskipTests`. If you want
-to supply custom `MAVEN_CLI_OPTS` and skip tests at the same time, don't forget
-to explicitly add `-DskipTests` to your options.
-If you still need to run tests during `mvn install`, add `-DskipTests=false` to
-`MAVEN_CLI_OPTS`.
-
-### Selecting the version of Python
-
-> [Introduced](https://gitlab.com/gitlab-org/security-products/license-management/merge_requests/36) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
-
-License Compliance uses Python 3.5 and pip 19.1 by default.
-If your project requires Python 2, you can switch to Python 2.7 and pip 10.0
-by setting the `LM_PYTHON_VERSION` environment variable to `2`.
-
-```yaml
-include:
- template: License-Management.gitlab-ci.yml
-
-license_management:
- variables:
- LM_PYTHON_VERSION: 2
-```
-
-## Project policies for License Compliance
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5940)
-in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.4.
-
-From the project's settings:
-
-- The list of licenses and their status can be managed.
-- Licenses can be manually approved or blacklisted.
-
-To approve or blacklist a license:
-
-1. Either use the **Manage licenses** button in the merge request widget, or
- navigate to the project's **Settings > CI/CD** and expand the
- **License Compliance** section.
-1. Click the **Add a license** button.
-
- ![License Compliance Add License](img/license_management_add_license.png)
-
-1. In the **License name** dropdown, either:
- - Select one of the available licenses. You can search for licenses in the field
- at the top of the list.
- - Enter arbitrary text in the field at the top of the list. This will cause the text to be
- added as a license name to the list.
-1. Select the **Approve** or **Blacklist** radio button to approve or blacklist respectively
- the selected license.
-
-To modify an existing license:
-
-1. In the **License Compliance** list, click the **Approved/Declined** dropdown to change it to the desired status.
-
- ![License Compliance Settings](img/license_management_settings.png)
-
-Searching for Licenses:
-
-1. Use the **Search** box to search for a specific license.
-
- ![License Compliance Search](img/license_management_search.png)
-
-## License Compliance report under pipelines
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5491)
-in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.2.
-
-From your project's left sidebar, navigate to **CI/CD > Pipelines** and click on the
-pipeline ID that has a `license_management` job to see the Licenses tab with the listed
-licenses (if any).
-
-![License Compliance Pipeline Tab](img/license_management_pipeline_tab.png)
-
-<!-- ## Troubleshooting
-
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
-
-Each scenario can be a third-level heading, e.g. `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+This document was moved to [another location](../license_compliance/index.md).
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index ac8c1ac0354..314f7c1766f 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -62,6 +62,9 @@ Once you're on the dashboard, at the top you should see a series of filters for:
- Report type
- Project
+NOTE: **Note:**
+The dashboard only shows projects with [security reports](#supported-reports) enabled in a group.
+
![dashboard with action buttons and metrics](img/group_security_dashboard.png)
Selecting one or more filters will filter the results in this page.
diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md
index 096730f800c..743d708399c 100644
--- a/doc/user/clusters/applications.md
+++ b/doc/user/clusters/applications.md
@@ -225,8 +225,7 @@ file.
## Upgrading applications
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24789)
-in GitLab 11.8.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24789) in GitLab 11.8.
The applications below can be upgraded.
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index af37cc896ad..72beb38fe76 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -314,15 +314,18 @@ Source:
#### Git and container registry failed authentication ban
-GitLab.com responds with HTTP status code 403 for 1 hour, if 30 failed
+GitLab.com responds with HTTP status code `403` for 1 hour, if 30 failed
authentication requests were received in a 3-minute period from a single IP address.
This applies only to Git requests and container registry (`/jwt/auth`) requests
(combined).
-This limit is reset by requests that authenticate successfully. For example, 29
-failed authentication requests followed by 1 successful request, followed by 29
-more failed authentication requests would not trigger a ban.
+This limit:
+
+- Is reset by requests that authenticate successfully. For example, 29
+ failed authentication requests followed by 1 successful request, followed by 29
+ more failed authentication requests would not trigger a ban.
+- Does not apply to JWT requests authenticated by `gitlab-ci-token`.
No response headers are provided.
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 17bbed2945d..840e1856dd9 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -181,9 +181,6 @@ graph TD;
#### Subgraphs
-NOTE: **Note:** GitLab 12.1 and up now [requires quotes around subgraph
-titles that contain multiple words](https://github.com/knsv/mermaid/pull/845).
-
Subgraphs can also be included:
~~~
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 80d1bf992ec..c28a5e49ec4 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -204,27 +204,29 @@ Any user can remove themselves from a group, unless they are the last Owner of
the group. The following table depicts the various user permission levels in a
group.
-| Action | Guest | Reporter | Developer | Maintainer | Owner |
-|-------------------------------------------------|-------|----------|-----------|------------|-------|
-| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View Insights charts **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View group epic **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Create/edit group epic **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
-| Manage group labels | | ✓ | ✓ | ✓ | ✓ |
-| Create project in group | | | ✓ | ✓ | ✓ |
-| Create/edit/delete group milestones | | | ✓ | ✓ | ✓ |
-| Enable/disable a dependency proxy **(PREMIUM)** | | | ✓ | ✓ | ✓ |
-| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
-| Create subgroup | | | | ✓ (1) | ✓ |
-| Edit group | | | | | ✓ |
-| Manage group members | | | | | ✓ |
-| Remove group | | | | | ✓ |
-| Delete group epic **(ULTIMATE)** | | | | | ✓ |
-| View group Audit Events | | | | | ✓ |
-| Disable notification emails | | | | | ✓ |
+| Action | Guest | Reporter | Developer | Maintainer | Owner |
+|--------------------------------------------------------|-------|----------|-----------|------------|-------|
+| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View Insights charts **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View group epic **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| Create/edit group epic **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
+| Manage group labels | | ✓ | ✓ | ✓ | ✓ |
+| Create project in group | | | ✓ | ✓ | ✓ |
+| Create/edit/delete group milestones | | | ✓ | ✓ | ✓ |
+| Enable/disable a dependency proxy **(PREMIUM)** | | | ✓ | ✓ | ✓ |
+| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
+| Create subgroup | | | | ✓ (1) | ✓ |
+| Edit group | | | | | ✓ |
+| Manage group members | | | | | ✓ |
+| Remove group | | | | | ✓ |
+| Delete group epic **(ULTIMATE)** | | | | | ✓ |
+| Edit epic comments (posted by any user) **(ULTIMATE)** | | | | ✓ (2) | ✓ (2) |
+| View group Audit Events | | | | | ✓ |
+| Disable notification emails | | | | | ✓ |
- (1): Groups can be set to [allow either Owners or Owners and
Maintainers to create subgroups](group/subgroups/index.md#creating-a-subgroup)
+- (2): Introduced in GitLab 12.2.
### Subgroup permissions
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index cf3a3fef79f..3bde0a375c6 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -199,7 +199,7 @@ To add an existing Kubernetes cluster to your project:
kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}'
```
- - **CA certificate** (required) - A valid Kubernetes certificate is needed to authenticate to the EKS cluster. We will use the certificate created by default.
+ - **CA certificate** (required) - A valid Kubernetes certificate is needed to authenticate to the cluster. We will use the certificate created by default.
- List the secrets with `kubectl get secrets`, and one should named similar to
`default-token-xxxxx`. Copy that token name for use below.
- Get the certificate by running this command:
diff --git a/doc/user/project/img/protected_branches_devs_can_push.png b/doc/user/project/img/protected_branches_devs_can_push.png
deleted file mode 100644
index b537839c00b..00000000000
--- a/doc/user/project/img/protected_branches_devs_can_push.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/protected_branches_devs_can_push_v12_3.png b/doc/user/project/img/protected_branches_devs_can_push_v12_3.png
new file mode 100644
index 00000000000..adc03a41abb
--- /dev/null
+++ b/doc/user/project/img/protected_branches_devs_can_push_v12_3.png
Binary files differ
diff --git a/doc/user/project/img/protected_branches_list.png b/doc/user/project/img/protected_branches_list.png
deleted file mode 100644
index 495ce4d7b6f..00000000000
--- a/doc/user/project/img/protected_branches_list.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/protected_branches_list_v12_3.png b/doc/user/project/img/protected_branches_list_v12_3.png
new file mode 100644
index 00000000000..365d8d99e5a
--- /dev/null
+++ b/doc/user/project/img/protected_branches_list_v12_3.png
Binary files differ
diff --git a/doc/user/project/img/protected_branches_page.png b/doc/user/project/img/protected_branches_page.png
deleted file mode 100644
index 9b10991f62e..00000000000
--- a/doc/user/project/img/protected_branches_page.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/protected_branches_page_v12_3.png b/doc/user/project/img/protected_branches_page_v12_3.png
new file mode 100644
index 00000000000..17f19642552
--- /dev/null
+++ b/doc/user/project/img/protected_branches_page_v12_3.png
Binary files differ
diff --git a/doc/user/project/img/protected_tags_list.png b/doc/user/project/img/protected_tags_list.png
deleted file mode 100644
index 6c5295e0f4b..00000000000
--- a/doc/user/project/img/protected_tags_list.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/protected_tags_list_v12_3.png b/doc/user/project/img/protected_tags_list_v12_3.png
new file mode 100644
index 00000000000..6a30f615f2f
--- /dev/null
+++ b/doc/user/project/img/protected_tags_list_v12_3.png
Binary files differ
diff --git a/doc/user/project/img/protected_tags_page.png b/doc/user/project/img/protected_tags_page.png
deleted file mode 100644
index 5f8a2106cd1..00000000000
--- a/doc/user/project/img/protected_tags_page.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/protected_tags_page_v12_3.png b/doc/user/project/img/protected_tags_page_v12_3.png
new file mode 100644
index 00000000000..841e19af8a7
--- /dev/null
+++ b/doc/user/project/img/protected_tags_page_v12_3.png
Binary files differ
diff --git a/doc/user/project/img/protected_tags_permissions_dropdown.png b/doc/user/project/img/protected_tags_permissions_dropdown.png
deleted file mode 100644
index 77098eeb591..00000000000
--- a/doc/user/project/img/protected_tags_permissions_dropdown.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/protected_tags_permissions_dropdown_v12_3.png b/doc/user/project/img/protected_tags_permissions_dropdown_v12_3.png
new file mode 100644
index 00000000000..913d4725d53
--- /dev/null
+++ b/doc/user/project/img/protected_tags_permissions_dropdown_v12_3.png
Binary files differ
diff --git a/doc/user/project/import/tfvc.md b/doc/user/project/import/tfvc.md
index 375522b77d0..9b148224e10 100644
--- a/doc/user/project/import/tfvc.md
+++ b/doc/user/project/import/tfvc.md
@@ -6,7 +6,7 @@ type: concepts
Team Foundation Server (TFS), renamed [Azure DevOps Server](https://azure.microsoft.com/en-us/services/devops/server/)
in 2019, is a set of tools developed by Microsoft which also includes
-[Team Foundation Version Control](https://docs.microsoft.com/en-us/azure/devops/repos/tfvc/overview)
+[Team Foundation Version Control](https://docs.microsoft.com/en-us/azure/devops/repos/tfvc/overview?view=azure-devops)
(TFVC), a centralized version control system similar to Git.
In this document, we focus on the TFVC to Git migration.
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index 64c4066683b..c63d5308536 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -98,7 +98,7 @@ When you create a project in GitLab, you'll have access to a large number of
- [Maven packages](packages/maven_repository.md): your private Maven repository in GitLab. **(PREMIUM)**
- [NPM packages](packages/npm_registry.md): your private NPM package registry in GitLab. **(PREMIUM)**
- [Code owners](code_owners.md): specify code owners for certain files **(STARTER)**
-- [License Compliance](../application_security/license_management/index.md): approve and blacklist licenses for projects. **(ULTIMATE)**
+- [License Compliance](../application_security/license_compliance/index.md): approve and blacklist licenses for projects. **(ULTIMATE)**
- [Dependency List](../application_security/dependency_list/index.md): view project dependencies. **(ULTIMATE)**
### Project integrations
diff --git a/doc/user/project/integrations/mattermost.md b/doc/user/project/integrations/mattermost.md
index 6e0f39956d3..c240b6cb6b4 100644
--- a/doc/user/project/integrations/mattermost.md
+++ b/doc/user/project/integrations/mattermost.md
@@ -13,8 +13,13 @@ To enable Mattermost integration you must create an incoming webhook integration
1. Choose a display name, description and channel, those can be overridden on GitLab.
1. Save it, copy the **Webhook URL**, we'll need this later for GitLab.
-There might be some cases that Incoming Webhooks are blocked by admin, ask your mattermost admin to enable
-it on **Mattermost System Console > Integrations > Integration Management**, or on **Mattermost System Console > Integrations > Custom Integrations** in Mattermost versions 5.11 and earlier.
+Incoming Webhooks might be blocked on your Mattermost instance. Ask your Mattermost admin
+to enable it on:
+
+- **Mattermost System Console > Integrations > Integration Management** in Mattermost
+ versions 5.12 and later.
+- **Mattermost System Console > Integrations > Custom Integrations** in Mattermost
+ versions 5.11 and earlier.
Display name override is not enabled by default, you need to ask your admin to enable it on that same section.
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index a80332adc46..d13592559b9 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -19,7 +19,7 @@ Once enabled, GitLab will automatically detect metrics from known services in th
### Managed Prometheus on Kubernetes
-> **Note**: [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/28916) in GitLab 10.5
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/28916) in GitLab 10.5.
GitLab can seamlessly deploy and manage Prometheus on a [connected Kubernetes cluster](../clusters/index.md), making monitoring of your apps easy.
@@ -271,7 +271,7 @@ Note the following properties:
### Downloading data as CSV
-Data from Prometheus charts on the metrics dashboard can be downloaded as CSV.
+Data from Prometheus charts on the metrics dashboard can be downloaded as CSV.
![Downloading as CSV](img/download_as_csv.png)
@@ -342,15 +342,21 @@ If the metric exceeds the threshold of the alert for over 5 minutes, an email wi
## Determining the performance impact of a merge
-> [Introduced][ce-10408] in GitLab 9.2.
-> GitLab 9.3 added the [numeric comparison](https://gitlab.com/gitlab-org/gitlab-ce/issues/27439) of the 30 minute averages.
-> Requires [Kubernetes](prometheus_library/kubernetes.md) metrics
+> - [Introduced][ce-10408] in GitLab 9.2.
+> - GitLab 9.3 added the [numeric comparison](https://gitlab.com/gitlab-org/gitlab-ce/issues/27439) of the 30 minute averages.
Developers can view the performance impact of their changes within the merge
-request workflow. When a source branch has been deployed to an environment, a sparkline and numeric comparison of the average memory consumption will appear. On the sparkline, a dot
-indicates when the current changes were deployed, with up to 30 minutes of
-performance data displayed before and after. The comparison shows the difference between the 30 minute average before and after the deployment. This information is updated after
-each commit has been deployed.
+request workflow.
+
+NOTE: **Note:**
+Requires [Kubernetes](prometheus_library/kubernetes.md) metrics.
+
+When a source branch has been deployed to an environment, a sparkline and
+numeric comparison of the average memory consumption will appear. On the
+sparkline, a dot indicates when the current changes were deployed, with up to 30 minutes of
+performance data displayed before and after. The comparison shows the difference
+between the 30 minute average before and after the deployment. This information
+is updated after each commit has been deployed.
Once merged and the target branch has been redeployed, the metrics will switch
to show the new environments this revision has been deployed to.
@@ -363,13 +369,15 @@ Prometheus server.
## Embedding metric charts within GitLab Flavored Markdown
> [Introduced][ce-29691] in GitLab 12.2.
-> Requires [Kubernetes](prometheus_library/kubernetes.md) metrics.
It is possible to display metrics charts within [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm).
+NOTE: **Note:**
+Requires [Kubernetes](prometheus_library/kubernetes.md) metrics.
+
To display a metric chart, include a link of the form `https://<root_url>/<project>/environments/<environment_id>/metrics`.
-A single chart may also be embedded. You can generate a link to the chart via the dropdown located on the right side of the chart:
+A single chart may also be embedded. You can generate a link to the chart via the dropdown located on the right side of the chart:
![Generate Link To Chart](img/generate_link_to_chart.png)
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index 04db54872d3..a94057dc3a1 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -41,7 +41,7 @@ With **[GitLab Enterprise Edition][ee]**, you can also:
- View the deployment process across projects with [Multi-Project Pipelines](../../../ci/multi_project_pipelines.md) **(PREMIUM)**
- Request [approvals](merge_request_approvals.md) from your managers **(STARTER)**
- Analyze the impact of your changes with [Code Quality reports](code_quality.md) **(STARTER)**
-- Manage the licenses of your dependencies with [License Compliance](../../application_security/license_management/index.md) **(ULTIMATE)**
+- Manage the licenses of your dependencies with [License Compliance](../../application_security/license_compliance/index.md) **(ULTIMATE)**
- Analyze your source code for vulnerabilities with [Static Application Security Testing](../../application_security/sast/index.md) **(ULTIMATE)**
- Analyze your running web applications for vulnerabilities with [Dynamic Application Security Testing](../../application_security/dast/index.md) **(ULTIMATE)**
- Analyze your dependencies for vulnerabilities with [Dependency Scanning](../../application_security/dependency_scanning/index.md) **(ULTIMATE)**
@@ -57,7 +57,7 @@ A. Consider you are a software developer working in a team:
1. You gather feedback from your team
1. You work on the implementation optimizing code with [Code Quality reports](code_quality.md) **(STARTER)**
1. You verify your changes with [JUnit test reports](../../../ci/junit_test_reports.md) in GitLab CI/CD
-1. You avoid using dependencies whose license is not compatible with your project with [License Compliance reports](license_management.md) **(ULTIMATE)**
+1. You avoid using dependencies whose license is not compatible with your project with [License Compliance reports](../../application_security/license_compliance/index.md) **(ULTIMATE)**
1. You request the [approval](#merge-request-approvals-starter) from your manager
1. Your manager pushes a commit with their final review, [approves the merge request](merge_request_approvals.md), and set it to [merge when pipeline succeeds](#merge-when-pipeline-succeeds) (Merge Request Approvals are available in GitLab Starter)
1. Your changes get deployed to production with [manual actions](../../../ci/yaml/README.md#whenmanual) for GitLab CI/CD
diff --git a/doc/user/project/merge_requests/license_management.md b/doc/user/project/merge_requests/license_management.md
index 93116ebd7c6..df5bd073ade 100644
--- a/doc/user/project/merge_requests/license_management.md
+++ b/doc/user/project/merge_requests/license_management.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../../application_security/license_management/index.md'
+redirect_to: '../../application_security/license_compliance/index.md'
---
-This document was moved to [another location](../../application_security/license_management/index.md).
+This document was moved to [another location](../../application_security/license_compliance/index.md).
diff --git a/doc/user/project/operations/feature_flags.md b/doc/user/project/operations/feature_flags.md
index 75b0623e6b0..6536a1a0a4b 100644
--- a/doc/user/project/operations/feature_flags.md
+++ b/doc/user/project/operations/feature_flags.md
@@ -85,7 +85,7 @@ NOTE: **NOTE**
We'd highly recommend you to use the [Environment](../../../ci/environments.md)
feature in order to quickly assess which flag is enabled per environment.
-## Rollout Strategy
+## Rollout strategy
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/8240) in GitLab 12.2.
@@ -97,33 +97,38 @@ However, a feature will be enabled for 50% of logged-in users if the matching en
### All users
-Enables the feature for all users.
-
-**All users** is implemented using the Unleash [default](https://unleash.github.io/docs/activation_strategy#default) activation strategy.
+Enables the feature for all users. It is implemented using the Unleash
+[`default`](https://unleash.github.io/docs/activation_strategy#default)
+activation strategy.
### Percent rollout (logged in users)
-**Percent rollout (logged in users)** enables the feature for a percentage of authenticated users. Set a value of 15%, for example, to enable the feature for 15% of authenticated users.
+Enables the feature for a percentage of authenticated users. It is
+implemented using the Unleash
+[`gradualRolloutUserId`](https://unleash.github.io/docs/activation_strategy#gradualrolloutuserid)
+activation strategy.
+
+Set a value of 15%, for example, to enable the feature for 15% of authenticated users.
A rollout percentage may be between 0% and 100%.
CAUTION: **Caution:**
-If this strategy is selected, then the Unleash client **must** be given a user id for the feature to be enabled. See the [Ruby example](#ruby-application-example) below.
+If this strategy is selected, then the Unleash client **must** be given a user
+ID for the feature to be enabled. See the [Ruby example](#ruby-application-example) below.
-**Percent rollout (logged in users)** is implemented using the Unleash [gradualRolloutUserId](https://unleash.github.io/docs/activation_strategy#gradualrolloutuserid) activation strategy.
-
-## Target Users
+## Target users
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/8240) in GitLab 12.2.
-A feature flag may be enabled for a list of target users.
+A feature flag may be enabled for a list of target users. It is implemented
+using the Unleash [`userWithId`](https://unleash.github.io/docs/activation_strategy#userwithid)
+activation strategy.
![Feature flag target users](img/target_users_v12_2.png)
CAUTION: **Caution:**
-The Unleash client **must** be given a user id for the feature to be enabled for target users. See the [Ruby example](#ruby-application-example) below.
-
-**Target users** is implemented using the Unleash [userWithId](https://unleash.github.io/docs/activation_strategy#userwithid) activation strategy.
+The Unleash client **must** be given a user ID for the feature to be enabled for
+target users. See the [Ruby example](#ruby-application-example) below.
## Integrating with your application
diff --git a/doc/user/project/operations/tracing.md b/doc/user/project/operations/tracing.md
index b92d2e49839..3fb3be3c21f 100644
--- a/doc/user/project/operations/tracing.md
+++ b/doc/user/project/operations/tracing.md
@@ -17,8 +17,8 @@ systems.
### Deploying Jaeger
To learn more about deploying Jaeger, read the official
-[Getting Started documentation](https://www.jaegertracing.io/docs/1.13/getting-started/).
-There is an easy to use [all-in-one Docker image](https://www.jaegertracing.io/docs/1.13/getting-started/#AllinoneDockerimage),
+[Getting Started documentation](https://www.jaegertracing.io/docs/latest/getting-started/).
+There is an easy to use [all-in-one Docker image](https://www.jaegertracing.io/docs/latest/getting-started/#AllinoneDockerimage),
as well as deployment options for [Kubernetes](https://github.com/jaegertracing/jaeger-kubernetes)
and [OpenShift](https://github.com/jaegertracing/jaeger-openshift).
@@ -27,7 +27,7 @@ and [OpenShift](https://github.com/jaegertracing/jaeger-openshift).
GitLab provides an easy way to open the Jaeger UI from within your project:
1. [Set up Jaeger](#deploying-jaeger) and configure your application using one of the
- [client libraries](https://www.jaegertracing.io/docs/1.13/client-libraries/).
+ [client libraries](https://www.jaegertracing.io/docs/latest/client-libraries/).
1. Navigate to your project's **Settings > Operations** and provide the Jaeger URL.
1. Click **Save changes** for the changes to take effect.
1. You can now visit **Operations > Tracing** in your project's sidebar and
diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md
index 7a79cdbcaee..8423b962948 100644
--- a/doc/user/project/protected_branches.md
+++ b/doc/user/project/protected_branches.md
@@ -34,11 +34,11 @@ that the `master` branch is protected by default.
1. From the **Branch** dropdown menu, select the branch you want to protect and
click **Protect**. In the screenshot below, we chose the `develop` branch.
- ![Protected branches page](img/protected_branches_page.png)
+ ![Protected branches page](img/protected_branches_page_v12_3.png)
1. Once done, the protected branch will appear in the "Protected branches" list.
- ![Protected branches list](img/protected_branches_list.png)
+ ![Protected branches list](img/protected_branches_list_v12_3.png)
## Using the Allowed to merge and Allowed to push settings
@@ -65,7 +65,7 @@ You can set the "Allowed to push" and "Allowed to merge" options while creating
a protected branch or afterwards by selecting the option you want from the
dropdown list in the "Already protected" area.
-![Developers can push](img/protected_branches_devs_can_push.png)
+![Developers can push](img/protected_branches_devs_can_push_v12_3.png)
If you don't choose any of those options while creating a protected branch,
they are set to "Maintainers" by default.
diff --git a/doc/user/project/protected_tags.md b/doc/user/project/protected_tags.md
index 5cc3b8a7fc3..9651c8824ab 100644
--- a/doc/user/project/protected_tags.md
+++ b/doc/user/project/protected_tags.md
@@ -24,15 +24,15 @@ To protect a tag, you need to have at least Maintainer permission level.
1. From the **Tag** dropdown menu, select the tag you want to protect or type and click **Create wildcard**. In the screenshot below, we chose to protect all tags matching `v*`:
- ![Protected tags page](img/protected_tags_page.png)
+ ![Protected tags page](img/protected_tags_page_v12_3.png)
1. From the **Allowed to create** dropdown, select who will have permission to create matching tags and then click **Protect**:
- ![Allowed to create tags dropdown](img/protected_tags_permissions_dropdown.png)
+ ![Allowed to create tags dropdown](img/protected_tags_permissions_dropdown_v12_3.png)
1. Once done, the protected tag will appear in the **Protected tags** list:
- ![Protected tags list](img/protected_tags_list.png)
+ ![Protected tags list](img/protected_tags_list_v12_3.png)
## Wildcard protected tags
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index bd966185c94..a838f06b2fd 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -73,7 +73,7 @@ according to the markup language.
| [Markdown](../../markdown.md) | `mdown`, `mkd`, `mkdn`, `md`, `markdown` |
| [reStructuredText](http://docutils.sourceforge.net/rst.html) | `rst` |
| [AsciiDoc](../../asciidoc.md) | `adoc`, `ad`, `asciidoc` |
-| [Textile](https://txstyle.org/) | `textile` |
+| [Textile](https://textile-lang.com/) | `textile` |
| [rdoc](http://rdoc.sourceforge.net/doc/index.html) | `rdoc` |
| [Orgmode](https://orgmode.org/) | `org` |
| [creole](http://www.wikicreole.org/) | `creole` |
diff --git a/doc/workflow/issue_weight.md b/doc/workflow/issue_weight.md
index a80519f0748..291646a430e 100644
--- a/doc/workflow/issue_weight.md
+++ b/doc/workflow/issue_weight.md
@@ -1,7 +1,6 @@
-# Issue Weight **(STARTER)**
+# Issue weight **(STARTER)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/76)
-> in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/76) in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
When you have a lot of issues, it can be hard to get an overview.
By adding a weight to each issue, you can get a better idea of how much time,
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index f545f33c06b..0bcd09d3977 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -216,6 +216,7 @@ module API
use :pagination
use :with_custom_attributes
+ use :optional_projects_params
end
get ":id/projects" do
projects = find_group_projects(params)
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 1aa6dc44bf7..5755f4b8d74 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -416,17 +416,7 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
def project_finder_params
- finder_params = { without_deleted: true }
- finder_params[:owned] = true if params[:owned].present?
- finder_params[:non_public] = true if params[:membership].present?
- finder_params[:starred] = true if params[:starred].present?
- finder_params[:visibility_level] = Gitlab::VisibilityLevel.level_value(params[:visibility]) if params[:visibility]
- finder_params[:archived] = archived_param unless params[:archived].nil?
- finder_params[:search] = params[:search] if params[:search]
- finder_params[:user] = params.delete(:user) if params[:user]
- finder_params[:custom_attributes] = params[:custom_attributes] if params[:custom_attributes]
- finder_params[:min_access_level] = params[:min_access_level] if params[:min_access_level]
- finder_params
+ project_finder_params_ce.merge(project_finder_params_ee)
end
# file helpers
@@ -461,6 +451,27 @@ module API
end
end
+ protected
+
+ def project_finder_params_ce
+ finder_params = { without_deleted: true }
+ finder_params[:owned] = true if params[:owned].present?
+ finder_params[:non_public] = true if params[:membership].present?
+ finder_params[:starred] = true if params[:starred].present?
+ finder_params[:visibility_level] = Gitlab::VisibilityLevel.level_value(params[:visibility]) if params[:visibility]
+ finder_params[:archived] = archived_param unless params[:archived].nil?
+ finder_params[:search] = params[:search] if params[:search]
+ finder_params[:user] = params.delete(:user) if params[:user]
+ finder_params[:custom_attributes] = params[:custom_attributes] if params[:custom_attributes]
+ finder_params[:min_access_level] = params[:min_access_level] if params[:min_access_level]
+ finder_params
+ end
+
+ # Overridden in EE
+ def project_finder_params_ee
+ {}
+ end
+
private
# rubocop:disable Gitlab/ModuleWithInstanceVariables
diff --git a/lib/api/helpers/groups_helpers.rb b/lib/api/helpers/groups_helpers.rb
index 2c33d79f6c8..6af12828ca5 100644
--- a/lib/api/helpers/groups_helpers.rb
+++ b/lib/api/helpers/groups_helpers.rb
@@ -28,6 +28,13 @@ module API
use :optional_params_ce
use :optional_params_ee
end
+
+ params :optional_projects_params_ee do
+ end
+
+ params :optional_projects_params do
+ use :optional_projects_params_ee
+ end
end
end
end
diff --git a/lib/gitlab.rb b/lib/gitlab.rb
index d9d8dcf7900..e8b938e46b1 100644
--- a/lib/gitlab.rb
+++ b/lib/gitlab.rb
@@ -55,7 +55,7 @@ module Gitlab
SUBDOMAIN_REGEX === Gitlab.config.gitlab.url
end
- def self.dev_env_or_com?
+ def self.dev_env_org_or_com?
Rails.env.development? || org? || com?
end
diff --git a/lib/gitlab/danger/teammate.rb b/lib/gitlab/danger/teammate.rb
index 8ae4ffdadb0..2789706aa3b 100644
--- a/lib/gitlab/danger/teammate.rb
+++ b/lib/gitlab/danger/teammate.rb
@@ -39,9 +39,9 @@ module Gitlab
def has_capability?(project, category, kind, labels)
case category
when :test
- area = role[/Test Automation Engineer(?:.*?, (\w+))/, 1].downcase
+ area = role[/Test Automation Engineer(?:.*?, (\w+))/, 1]
- area && labels.any?("devops::#{area}") if kind == :reviewer
+ area && labels.any?("devops::#{area.downcase}") if kind == :reviewer
else
capabilities(project).include?("#{kind} #{category}")
end
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 201db9fec26..d65c0d3e78d 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -50,7 +50,7 @@ module Gitlab
def self.interceptors
return [] unless Labkit::Tracing.enabled?
- [Labkit::Tracing::GRPCInterceptor.instance]
+ [Labkit::Tracing::GRPC::ClientInterceptor.instance]
end
private_class_method :interceptors
diff --git a/lib/gitlab/performance_bar/with_top_level_warnings.rb b/lib/gitlab/performance_bar/with_top_level_warnings.rb
new file mode 100644
index 00000000000..fb5c5c5959d
--- /dev/null
+++ b/lib/gitlab/performance_bar/with_top_level_warnings.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module PerformanceBar
+ module WithTopLevelWarnings
+ def results
+ results = super
+
+ results.merge(has_warnings: has_warnings?(results))
+ end
+
+ def has_warnings?(results)
+ results[:data].any? do |_, value|
+ value[:warnings].present?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/snowplow_tracker.rb b/lib/gitlab/snowplow_tracker.rb
deleted file mode 100644
index 9f12513e09e..00000000000
--- a/lib/gitlab/snowplow_tracker.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-require 'snowplow-tracker'
-
-module Gitlab
- module SnowplowTracker
- NAMESPACE = 'cf'
-
- class << self
- def track_event(category, action, label: nil, property: nil, value: nil, context: nil)
- tracker&.track_struct_event(category, action, label, property, value, context, Time.now.to_i)
- end
-
- private
-
- def tracker
- return unless enabled?
-
- @tracker ||= ::SnowplowTracker::Tracker.new(emitter, subject, NAMESPACE, Gitlab::CurrentSettings.snowplow_site_id)
- end
-
- def subject
- ::SnowplowTracker::Subject.new
- end
-
- def emitter
- ::SnowplowTracker::Emitter.new(Gitlab::CurrentSettings.snowplow_collector_hostname)
- end
-
- def enabled?
- Gitlab::CurrentSettings.snowplow_enabled?
- end
- end
- end
-end
diff --git a/lib/gitlab/tracking.rb b/lib/gitlab/tracking.rb
new file mode 100644
index 00000000000..ef669b03c87
--- /dev/null
+++ b/lib/gitlab/tracking.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'snowplow-tracker'
+
+module Gitlab
+ module Tracking
+ SNOWPLOW_NAMESPACE = 'gl'
+
+ class << self
+ def enabled?
+ Gitlab::CurrentSettings.snowplow_enabled?
+ end
+
+ def event(category, action, label: nil, property: nil, value: nil, context: nil)
+ return unless enabled?
+
+ snowplow.track_struct_event(category, action, label, property, value, context, Time.now.to_i)
+ end
+
+ def snowplow_options(group)
+ additional_features = Feature.enabled?(:additional_snowplow_tracking, group)
+ {
+ namespace: SNOWPLOW_NAMESPACE,
+ hostname: Gitlab::CurrentSettings.snowplow_collector_hostname,
+ cookie_domain: Gitlab::CurrentSettings.snowplow_cookie_domain,
+ app_id: Gitlab::CurrentSettings.snowplow_site_id,
+ page_tracking_enabled: additional_features,
+ activity_tracking_enabled: additional_features
+ }.transform_keys! { |key| key.to_s.camelize(:lower).to_sym }
+ end
+
+ private
+
+ def snowplow
+ @snowplow ||= SnowplowTracker::Tracker.new(
+ SnowplowTracker::Emitter.new(Gitlab::CurrentSettings.snowplow_collector_hostname),
+ SnowplowTracker::Subject.new,
+ SNOWPLOW_NAMESPACE,
+ Gitlab::CurrentSettings.snowplow_site_id
+ )
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index 3b77fe838ae..29087d26007 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -34,7 +34,8 @@ module Gitlab
GitConfigOptions: [],
GitalyServer: {
address: Gitlab::GitalyClient.address(project.repository_storage),
- token: Gitlab::GitalyClient.token(project.repository_storage)
+ token: Gitlab::GitalyClient.token(project.repository_storage),
+ features: Feature::Gitaly.server_feature_flags
}
}
@@ -250,7 +251,8 @@ module Gitlab
def gitaly_server_hash(repository)
{
address: Gitlab::GitalyClient.address(repository.project.repository_storage),
- token: Gitlab::GitalyClient.token(repository.project.repository_storage)
+ token: Gitlab::GitalyClient.token(repository.project.repository_storage),
+ features: Feature::Gitaly.server_feature_flags
}
end
diff --git a/lib/peek/views/active_record.rb b/lib/peek/views/active_record.rb
index 2d78818630d..a35783c1971 100644
--- a/lib/peek/views/active_record.rb
+++ b/lib/peek/views/active_record.rb
@@ -3,6 +3,24 @@
module Peek
module Views
class ActiveRecord < DetailedView
+ DEFAULT_THRESHOLDS = {
+ calls: 100,
+ duration: 3,
+ individual_call: 1
+ }.freeze
+
+ THRESHOLDS = {
+ production: {
+ calls: 100,
+ duration: 15,
+ individual_call: 5
+ }
+ }.freeze
+
+ def self.thresholds
+ @thresholds ||= THRESHOLDS.fetch(Rails.env.to_sym, DEFAULT_THRESHOLDS)
+ end
+
private
def setup_subscribers
diff --git a/lib/peek/views/detailed_view.rb b/lib/peek/views/detailed_view.rb
index f4ca1cb5075..4f3eddaf11b 100644
--- a/lib/peek/views/detailed_view.rb
+++ b/lib/peek/views/detailed_view.rb
@@ -3,11 +3,16 @@
module Peek
module Views
class DetailedView < View
+ def self.thresholds
+ {}
+ end
+
def results
{
- duration: formatted_duration,
+ duration: format_duration(duration),
calls: calls,
- details: details
+ details: details,
+ warnings: warnings
}
end
@@ -18,30 +23,48 @@ module Peek
private
def duration
- detail_store.map { |entry| entry[:duration] }.sum # rubocop:disable CodeReuse/ActiveRecord
+ detail_store.map { |entry| entry[:duration] }.sum * 1000 # rubocop:disable CodeReuse/ActiveRecord
end
def calls
detail_store.count
end
+ def details
+ call_details
+ .sort { |a, b| b[:duration] <=> a[:duration] }
+ .map(&method(:format_call_details))
+ end
+
+ def warnings
+ [
+ warning_for(calls, self.class.thresholds[:calls], label: "#{key} calls"),
+ warning_for(duration, self.class.thresholds[:duration], label: "#{key} duration")
+ ].flatten.compact
+ end
+
def call_details
detail_store
end
def format_call_details(call)
- call.merge(duration: (call[:duration] * 1000).round(3))
- end
+ duration = (call[:duration] * 1000).round(3)
- def details
- call_details
- .sort { |a, b| b[:duration] <=> a[:duration] }
- .map(&method(:format_call_details))
+ call.merge(duration: duration,
+ warnings: warning_for(duration, self.class.thresholds[:individual_call]))
end
- def formatted_duration
- ms = duration * 1000
+ def warning_for(actual, threshold, label: nil)
+ if threshold && actual > threshold
+ prefix = "#{label}: " if label
+
+ ["#{prefix}#{actual} over #{threshold}"]
+ else
+ []
+ end
+ end
+ def format_duration(ms)
if ms >= 1000
"%.2fms" % ms
else
diff --git a/lib/peek/views/gitaly.rb b/lib/peek/views/gitaly.rb
index 6ad6ddfd89d..f669feae254 100644
--- a/lib/peek/views/gitaly.rb
+++ b/lib/peek/views/gitaly.rb
@@ -3,6 +3,24 @@
module Peek
module Views
class Gitaly < DetailedView
+ DEFAULT_THRESHOLDS = {
+ calls: 30,
+ duration: 1,
+ individual_call: 0.5
+ }.freeze
+
+ THRESHOLDS = {
+ production: {
+ calls: 30,
+ duration: 1,
+ individual_call: 0.5
+ }
+ }.freeze
+
+ def self.thresholds
+ @thresholds ||= THRESHOLDS.fetch(Rails.env.to_sym, DEFAULT_THRESHOLDS)
+ end
+
private
def duration
diff --git a/lib/peek/views/rugged.rb b/lib/peek/views/rugged.rb
index 18b3f422852..3ed54a010f8 100644
--- a/lib/peek/views/rugged.rb
+++ b/lib/peek/views/rugged.rb
@@ -12,7 +12,7 @@ module Peek
private
def duration
- ::Gitlab::RuggedInstrumentation.query_time
+ ::Gitlab::RuggedInstrumentation.query_time_ms
end
def calls
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e44c18979cd..12138d2db3a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -309,6 +309,9 @@ msgstr ""
msgid "(external source)"
msgstr ""
+msgid "(removed)"
+msgstr ""
+
msgid "+ %{amount} more"
msgstr ""
@@ -12112,9 +12115,6 @@ msgstr ""
msgid "Toggles :%{name}: emoji award."
msgstr ""
-msgid "Token"
-msgstr ""
-
msgid "Tomorrow"
msgstr ""
diff --git a/package.json b/package.json
index 8fa34cdea28..50cd5f36d20 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,6 @@
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/preset-env": "^7.5.5",
- "@gitlab/csslab": "^1.9.0",
"@gitlab/svgs": "^1.70.0",
"@gitlab/ui": "5.19.0",
"@gitlab/visual-review-tools": "^1.0.0",
@@ -97,7 +96,7 @@
"jszip-utils": "^0.0.2",
"katex": "^0.10.0",
"marked": "^0.3.12",
- "mermaid": "^8.2.3",
+ "mermaid": "^8.2.4",
"monaco-editor": "^0.15.6",
"monaco-editor-webpack-plugin": "^1.7.0",
"mousetrap": "^1.4.6",
diff --git a/qa/README.md b/qa/README.md
index 16e5e730a6b..dede3cd2473 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -105,6 +105,17 @@ If you need to authenticate as a different user, you can provide the
GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password bundle exec bin/qa Test::Instance::All https://gitlab.example.com
```
+Some QA tests require logging in as an admin user. By default, the QA
+tests will use the the same `root` user seeded by the GDK.
+
+If you need to authenticate with different admin credentials, you can
+provide the `GITLAB_ADMIN_USERNAME` and `GITLAB_ADMIN_PASSWORD`
+environment variables:
+
+```
+GITLAB_ADMIN_USERNAME=admin GITLAB_ADMIN_PASSWORD=myadminpassword GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password bundle exec bin/qa Test::Instance::All https://gitlab.example.com
+```
+
If your user doesn't have permission to default sandbox group
`gitlab-qa-sandbox`, you could also use another sandbox group by giving
`GITLAB_SANDBOX_NAME`:
diff --git a/qa/qa.rb b/qa/qa.rb
index a760f72f70d..2c11df1f15a 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -160,6 +160,10 @@ module QA
module Group
autoload :New, 'qa/page/group/new'
autoload :Show, 'qa/page/group/show'
+
+ module Settings
+ autoload :General, 'qa/page/group/settings/general'
+ end
end
module File
@@ -207,6 +211,7 @@ module QA
autoload :Main, 'qa/page/project/settings/main'
autoload :Repository, 'qa/page/project/settings/repository'
autoload :CICD, 'qa/page/project/settings/ci_cd'
+ autoload :AutoDevops, 'qa/page/project/settings/auto_devops'
autoload :DeployKeys, 'qa/page/project/settings/deploy_keys'
autoload :DeployTokens, 'qa/page/project/settings/deploy_tokens'
autoload :ProtectedBranches, 'qa/page/project/settings/protected_branches'
@@ -303,8 +308,10 @@ module QA
autoload :Repository, 'qa/page/admin/settings/repository'
autoload :General, 'qa/page/admin/settings/general'
autoload :MetricsAndProfiling, 'qa/page/admin/settings/metrics_and_profiling'
+ autoload :Network, 'qa/page/admin/settings/network'
module Component
+ autoload :IpLimits, 'qa/page/admin/settings/component/ip_limits'
autoload :RepositoryStorage, 'qa/page/admin/settings/component/repository_storage'
autoload :AccountAndLimit, 'qa/page/admin/settings/component/account_and_limit'
autoload :PerformanceBar, 'qa/page/admin/settings/component/performance_bar'
diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb
index 61ec9854726..a520fb546c8 100644
--- a/qa/qa/page/admin/menu.rb
+++ b/qa/qa/page/admin/menu.rb
@@ -49,6 +49,14 @@ module QA
end
end
+ def go_to_network_settings
+ hover_settings do
+ within_submenu do
+ click_element :admin_settings_network_item
+ end
+ end
+ end
+
private
def hover_settings
diff --git a/qa/qa/page/admin/settings/component/ip_limits.rb b/qa/qa/page/admin/settings/component/ip_limits.rb
new file mode 100644
index 00000000000..9db2ae8ba58
--- /dev/null
+++ b/qa/qa/page/admin/settings/component/ip_limits.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Admin
+ module Settings
+ module Component
+ class IpLimits < Page::Base
+ view 'app/views/admin/application_settings/_ip_limits.html.haml' do
+ element :throttle_unauthenticated_checkbox
+ element :throttle_authenticated_api_checkbox
+ element :throttle_authenticated_web_checkbox
+ element :save_changes_button
+ end
+
+ def enable_throttles
+ check_element :throttle_unauthenticated_checkbox
+ check_element :throttle_authenticated_api_checkbox
+ check_element :throttle_authenticated_web_checkbox
+ end
+
+ def save_settings
+ click_element :save_changes_button
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/admin/settings/network.rb b/qa/qa/page/admin/settings/network.rb
new file mode 100644
index 00000000000..fdb8fcda281
--- /dev/null
+++ b/qa/qa/page/admin/settings/network.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Admin
+ module Settings
+ class Network < Page::Base
+ include QA::Page::Settings::Common
+
+ view 'app/views/admin/application_settings/network.html.haml' do
+ element :ip_limits_section
+ end
+
+ def expand_ip_limits(&block)
+ expand_section(:ip_limits_section) do
+ Component::IpLimits.perform(&block)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/group/settings/general.rb b/qa/qa/page/group/settings/general.rb
new file mode 100644
index 00000000000..07b421f154a
--- /dev/null
+++ b/qa/qa/page/group/settings/general.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module Settings
+ class General < QA::Page::Base
+ view 'app/views/groups/edit.html.haml' do
+ element :permission_lfs_2fa_section
+ end
+ view 'app/views/groups/settings/_permissions.html.haml' do
+ element :save_permissions_changes_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/settings/auto_devops.rb b/qa/qa/page/project/settings/auto_devops.rb
new file mode 100644
index 00000000000..827d5b072c3
--- /dev/null
+++ b/qa/qa/page/project/settings/auto_devops.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Settings
+ class AutoDevops < Page::Base
+ view 'app/views/projects/settings/ci_cd/_autodevops_form.html.haml' do
+ element :enable_autodevops_checkbox
+ element :save_changes_button
+ end
+
+ def enable_autodevops
+ check_element :enable_autodevops_checkbox
+ click_element :save_changes_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/settings/ci_cd.rb b/qa/qa/page/project/settings/ci_cd.rb
index ae826fb3a32..45040cf4660 100644
--- a/qa/qa/page/project/settings/ci_cd.rb
+++ b/qa/qa/page/project/settings/ci_cd.rb
@@ -13,11 +13,6 @@ module QA
element :variables_settings_content
end
- view 'app/views/projects/settings/ci_cd/_autodevops_form.html.haml' do
- element :enable_autodevops_checkbox
- element :save_changes_button
- end
-
def expand_runners_settings(&block)
expand_section(:runners_settings_content) do
Settings::Runners.perform(&block)
@@ -30,10 +25,9 @@ module QA
end
end
- def enable_auto_devops
+ def expand_auto_devops(&block)
expand_section(:autodevops_settings_content) do
- check_element :enable_autodevops_checkbox
- click_element :save_changes_button
+ Settings::AutoDevops.perform(&block)
end
end
end
diff --git a/qa/qa/page/project/sub_menus/issues.rb b/qa/qa/page/project/sub_menus/issues.rb
index 8fb8fa06346..d27a250a300 100644
--- a/qa/qa/page/project/sub_menus/issues.rb
+++ b/qa/qa/page/project/sub_menus/issues.rb
@@ -10,6 +10,7 @@ module QA
def self.included(base)
base.class_eval do
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
+ element :issue_boards_link
element :issues_item
element :labels_link
element :milestones_link
@@ -29,6 +30,14 @@ module QA
end
end
+ def go_to_boards
+ hover_issues do
+ within_submenu do
+ click_element(:issue_boards_link)
+ end
+ end
+ end
+
def go_to_labels
hover_issues do
within_submenu do
diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb
index 37bca97fec7..7541baed467 100644
--- a/qa/qa/page/project/web_ide/edit.rb
+++ b/qa/qa/page/project/web_ide/edit.rb
@@ -34,6 +34,10 @@ module QA
element :dropdown_filter_input
end
+ view 'app/assets/javascripts/ide/components/commit_sidebar/actions.vue' do
+ element :commit_to_current_branch_radio
+ end
+
view 'app/assets/javascripts/ide/components/commit_sidebar/form.vue' do
element :begin_commit_button
element :commit_button
@@ -104,7 +108,7 @@ module QA
# animation is still in process even when the buttons have the
# expected visibility.
commit_success_msg_shown = retry_until do
- uncheck_element :start_new_mr_checkbox
+ click_element :commit_to_current_branch_radio
click_element :commit_button
wait(reload: false) do
diff --git a/qa/qa/resource/sandbox.rb b/qa/qa/resource/sandbox.rb
index e2b1c4c0831..6eff0e87ddc 100644
--- a/qa/qa/resource/sandbox.rb
+++ b/qa/qa/resource/sandbox.rb
@@ -7,7 +7,7 @@ module QA
# creating it if it doesn't yet exist.
#
class Sandbox < Base
- attr_reader :path
+ attr_accessor :path
attribute :id
diff --git a/qa/qa/runtime/api/client.rb b/qa/qa/runtime/api/client.rb
index 663be27a849..25d8f3c0fbb 100644
--- a/qa/qa/runtime/api/client.rb
+++ b/qa/qa/runtime/api/client.rb
@@ -8,11 +8,12 @@ module QA
class Client
attr_reader :address, :user
- def initialize(address = :gitlab, personal_access_token: nil, is_new_session: true, user: nil)
+ def initialize(address = :gitlab, personal_access_token: nil, is_new_session: true, user: nil, ip_limits: false)
@address = address
@personal_access_token = personal_access_token
@is_new_session = is_new_session
@user = user
+ enable_ip_limits if ip_limits
end
def personal_access_token
@@ -26,6 +27,24 @@ module QA
private
+ def enable_ip_limits
+ Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
+
+ Runtime::Browser.visit(@address, Page::Main::Login)
+ Page::Main::Login.perform(&:sign_in_using_admin_credentials)
+ Page::Main::Menu.perform(&:click_admin_area)
+ Page::Admin::Menu.perform(&:go_to_network_settings)
+
+ Page::Admin::Settings::Network.perform do |setting|
+ setting.expand_ip_limits do |page|
+ page.enable_throttles
+ page.save_settings
+ end
+ end
+
+ Page::Main::Menu.perform(&:sign_out)
+ end
+
def create_personal_access_token
Page::Main::Menu.perform(&:sign_out) if @is_new_session && Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
diff --git a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
new file mode 100644
index 00000000000..44c5e0b4196
--- /dev/null
+++ b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Manage with IP rate limits', :requires_admin do
+ describe 'Users API' do
+ before(:context) do
+ @api_client = Runtime::API::Client.new(:gitlab, ip_limits: true)
+ end
+
+ let(:request) { Runtime::API::Request.new(@api_client, '/users') }
+
+ it 'GET /users' do
+ 5.times do
+ get request.url
+ expect_status(200)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index 60c1e105ae6..3f99ae644c7 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -147,23 +147,31 @@ module QA
end
describe 'Auto DevOps', :smoke do
- it 'enables AutoDevOps by default' do
+ before do
login
- project = Resource::Project.fabricate! do |p|
- p.name = Runtime::Env.auto_devops_project_name || 'project-with-autodevops'
+ @project = Resource::Project.fabricate_via_browser_ui! do |p|
+ p.name = "project-with-autodevops-#{SecureRandom.hex(8)}"
p.description = 'Project with AutoDevOps'
end
+ Page::Project::Menu.perform(&:go_to_ci_cd_settings)
+ Page::Project::Settings::CICD.perform(&:expand_auto_devops)
+ Page::Project::Settings::AutoDevops.perform(&:enable_autodevops)
+
+ @project.visit!
+
# Create AutoDevOps repo
Resource::Repository::ProjectPush.fabricate! do |push|
- push.project = project
+ push.project = @project
push.directory = Pathname
.new(__dir__)
.join('../../../../../fixtures/auto_devops_rack')
push.commit_message = 'Create AutoDevOps compatible Project'
end
+ end
+ it 'runs an AutoDevOps pipeline' do
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
diff --git a/rubocop/cop/rspec/be_success_matcher.rb b/rubocop/cop/rspec/be_success_matcher.rb
new file mode 100644
index 00000000000..dce9604b3d7
--- /dev/null
+++ b/rubocop/cop/rspec/be_success_matcher.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module RSpec
+ # This cop checks for `be_success` usage in controller specs
+ #
+ # @example
+ #
+ # # bad
+ # it "responds with success" do
+ # expect(response).to be_success
+ # end
+ #
+ # it { is_expected.to be_success }
+ #
+ # # good
+ # it "responds with success" do
+ # expect(response).to be_successful
+ # end
+ #
+ # it { is_expected.to be_successful }
+ #
+ class BeSuccessMatcher < RuboCop::Cop::Cop
+ MESSAGE = 'Do not use deprecated `success?` method, use `successful?` instead.'
+
+ def_node_search :expect_to_be_success?, <<~PATTERN
+ (send (send nil? :expect (send nil? ...)) {:to :not_to :to_not} (send nil? :be_success))
+ PATTERN
+
+ def_node_search :is_expected_to_be_success?, <<~PATTERN
+ (send (send nil? :is_expected) {:to :not_to :to_not} (send nil? :be_success))
+ PATTERN
+
+ def be_success_usage?(node)
+ expect_to_be_success?(node) || is_expected_to_be_success?(node)
+ end
+
+ def on_send(node)
+ return unless be_success_usage?(node)
+
+ add_offense(node, location: :expression, message: MESSAGE)
+ end
+
+ def autocorrect(node)
+ lambda do |corrector|
+ corrector.insert_after(node.loc.expression, 'ful')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index d1328c4eb38..c342df6d6c9 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -31,6 +31,7 @@ require_relative 'cop/migration/timestamps'
require_relative 'cop/migration/update_column_in_batches'
require_relative 'cop/migration/update_large_table'
require_relative 'cop/project_path_helper'
+require_relative 'cop/rspec/be_success_matcher'
require_relative 'cop/rspec/env_assignment'
require_relative 'cop/rspec/factories_in_migration_specs'
require_relative 'cop/rspec/top_level_describe_path'
diff --git a/spec/controllers/boards/lists_controller_spec.rb b/spec/controllers/boards/lists_controller_spec.rb
index 418ca6f3210..1e8a8145b35 100644
--- a/spec/controllers/boards/lists_controller_spec.rb
+++ b/spec/controllers/boards/lists_controller_spec.rb
@@ -30,6 +30,21 @@ describe Boards::ListsController do
expect(json_response.length).to eq 3
end
+ it 'avoids n+1 queries when serializing lists' do
+ list_1 = create(:list, board: board)
+ list_1.update_preferences_for(user, { collapsed: true })
+
+ control_count = ActiveRecord::QueryRecorder.new { read_board_list user: user, board: board }.count
+
+ list_2 = create(:list, board: board)
+ list_2.update_preferences_for(user, { collapsed: true })
+
+ list_3 = create(:list, board: board)
+ list_3.update_preferences_for(user, { collapsed: true })
+
+ expect { read_board_list user: user, board: board }.not_to exceed_query_limit(control_count)
+ end
+
context 'with unauthorized user' do
let(:unauth_user) { create(:user) }
@@ -154,6 +169,22 @@ describe Boards::ListsController do
end
end
+ context 'with collapsed preference' do
+ it 'saves collapsed preference for user' do
+ save_setting user: user, board: board, list: planning, setting: { collapsed: true }
+
+ expect(planning.preferences_for(user).collapsed).to eq(true)
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'saves not collapsed preference for user' do
+ save_setting user: user, board: board, list: planning, setting: { collapsed: false }
+
+ expect(planning.preferences_for(user).collapsed).to eq(false)
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+
def move(user:, board:, list:, position:)
sign_in(user)
@@ -166,6 +197,19 @@ describe Boards::ListsController do
patch :update, params: params, as: :json
end
+
+ def save_setting(user:, board:, list:, setting: {})
+ sign_in(user)
+
+ params = { namespace_id: project.namespace.to_param,
+ project_id: project,
+ board_id: board.to_param,
+ id: list.to_param,
+ list: setting,
+ format: :json }
+
+ patch :update, params: params, as: :json
+ end
end
describe 'DELETE destroy' do
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 4ad90c96558..0d5f5df71b6 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -282,10 +282,6 @@ describe "Admin Runners" do
visit admin_runner_path(runner)
end
- describe 'runner info' do
- it { expect(find_field('runner_token').value).to eq runner.token }
- end
-
describe 'projects' do
it 'contains project names' do
expect(page).to have_content(@project1.full_name)
diff --git a/spec/features/dashboard/todos/todos_filtering_spec.rb b/spec/features/dashboard/todos/todos_filtering_spec.rb
index f273e416597..efa163042f9 100644
--- a/spec/features/dashboard/todos/todos_filtering_spec.rb
+++ b/spec/features/dashboard/todos/todos_filtering_spec.rb
@@ -31,9 +31,9 @@ describe 'Dashboard > User filters todos', :js do
end
it 'displays all todos without a filter' do
- expect(page).to have_content issue1.to_reference(full: true)
- expect(page).to have_content merge_request.to_reference(full: true)
- expect(page).to have_content issue2.to_reference(full: true)
+ expect(page).to have_content issue1.to_reference(full: false)
+ expect(page).to have_content merge_request.to_reference(full: false)
+ expect(page).to have_content issue2.to_reference(full: false)
end
it 'filters by project' do
@@ -58,9 +58,9 @@ describe 'Dashboard > User filters todos', :js do
wait_for_requests
- expect(page).to have_content issue1.to_reference(full: true)
- expect(page).to have_content merge_request.to_reference(full: true)
- expect(page).not_to have_content issue2.to_reference(full: true)
+ expect(page).to have_content "issue #{issue1.to_reference} \"issue\" at #{group1.name} / project_1"
+ expect(page).to have_content "merge request #{merge_request.to_reference}"
+ expect(page).not_to have_content "issue #{issue2.to_reference} \"issue\" at #{group2.name} / project_3"
end
context 'Author filter' do
diff --git a/spec/features/dashboard/todos/todos_sorting_spec.rb b/spec/features/dashboard/todos/todos_sorting_spec.rb
index 3870c661784..421a66c6d48 100644
--- a/spec/features/dashboard/todos/todos_sorting_spec.rb
+++ b/spec/features/dashboard/todos/todos_sorting_spec.rb
@@ -42,33 +42,33 @@ describe 'Dashboard > User sorts todos' do
click_link 'Last created'
results_list = page.find('.todos-list')
- expect(results_list.all('p')[0]).to have_content('merge_request_1')
- expect(results_list.all('p')[1]).to have_content('issue_1')
- expect(results_list.all('p')[2]).to have_content('issue_3')
- expect(results_list.all('p')[3]).to have_content('issue_2')
- expect(results_list.all('p')[4]).to have_content('issue_4')
+ expect(results_list.all('.todo-title')[0]).to have_content('merge_request_1')
+ expect(results_list.all('.todo-title')[1]).to have_content('issue_1')
+ expect(results_list.all('.todo-title')[2]).to have_content('issue_3')
+ expect(results_list.all('.todo-title')[3]).to have_content('issue_2')
+ expect(results_list.all('.todo-title')[4]).to have_content('issue_4')
end
it 'sorts with newest created todos first' do
click_link 'Oldest created'
results_list = page.find('.todos-list')
- expect(results_list.all('p')[0]).to have_content('issue_4')
- expect(results_list.all('p')[1]).to have_content('issue_2')
- expect(results_list.all('p')[2]).to have_content('issue_3')
- expect(results_list.all('p')[3]).to have_content('issue_1')
- expect(results_list.all('p')[4]).to have_content('merge_request_1')
+ expect(results_list.all('.todo-title')[0]).to have_content('issue_4')
+ expect(results_list.all('.todo-title')[1]).to have_content('issue_2')
+ expect(results_list.all('.todo-title')[2]).to have_content('issue_3')
+ expect(results_list.all('.todo-title')[3]).to have_content('issue_1')
+ expect(results_list.all('.todo-title')[4]).to have_content('merge_request_1')
end
it 'sorts by label priority' do
click_link 'Label priority'
results_list = page.find('.todos-list')
- expect(results_list.all('p')[0]).to have_content('issue_3')
- expect(results_list.all('p')[1]).to have_content('merge_request_1')
- expect(results_list.all('p')[2]).to have_content('issue_1')
- expect(results_list.all('p')[3]).to have_content('issue_2')
- expect(results_list.all('p')[4]).to have_content('issue_4')
+ expect(results_list.all('.todo-title')[0]).to have_content('issue_3')
+ expect(results_list.all('.todo-title')[1]).to have_content('merge_request_1')
+ expect(results_list.all('.todo-title')[2]).to have_content('issue_1')
+ expect(results_list.all('.todo-title')[3]).to have_content('issue_2')
+ expect(results_list.all('.todo-title')[4]).to have_content('issue_4')
end
end
@@ -93,9 +93,9 @@ describe 'Dashboard > User sorts todos' do
click_link 'Label priority'
results_list = page.find('.todos-list')
- expect(results_list.all('p')[0]).to have_content('issue_1')
- expect(results_list.all('p')[1]).to have_content('issue_2')
- expect(results_list.all('p')[2]).to have_content('merge_request_1')
+ expect(results_list.all('.todo-title')[0]).to have_content('issue_1')
+ expect(results_list.all('.todo-title')[1]).to have_content('issue_2')
+ expect(results_list.all('.todo-title')[2]).to have_content('merge_request_1')
end
end
end
diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb
index b98a04b0bda..867281da1e6 100644
--- a/spec/features/dashboard/todos/todos_spec.rb
+++ b/spec/features/dashboard/todos/todos_spec.rb
@@ -3,10 +3,10 @@
require 'spec_helper'
describe 'Dashboard Todos' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, username: 'john') }
let(:author) { create(:user) }
let(:project) { create(:project, :public) }
- let(:issue) { create(:issue, due_date: Date.today) }
+ let(:issue) { create(:issue, due_date: Date.today, title: "Fix bug") }
context 'User does not have todos' do
before do
@@ -135,7 +135,7 @@ describe 'Dashboard Todos' do
it 'shows issue assigned to yourself message' do
page.within('.js-todos-all') do
- expect(page).to have_content("You assigned issue #{issue.to_reference(full: true)} to yourself")
+ expect(page).to have_content("You assigned issue #{issue.to_reference} \"Fix bug\" at #{project.namespace.owner_name} / #{project.name} to yourself")
end
end
end
@@ -148,7 +148,7 @@ describe 'Dashboard Todos' do
it 'shows you added a todo message' do
page.within('.js-todos-all') do
- expect(page).to have_content("You added a todo for issue #{issue.to_reference(full: true)}")
+ expect(page).to have_content("You added a todo for issue #{issue.to_reference} \"Fix bug\" at #{project.namespace.owner_name} / #{project.name}")
expect(page).not_to have_content('to yourself')
end
end
@@ -162,7 +162,7 @@ describe 'Dashboard Todos' do
it 'shows you mentioned yourself message' do
page.within('.js-todos-all') do
- expect(page).to have_content("You mentioned yourself on issue #{issue.to_reference(full: true)}")
+ expect(page).to have_content("You mentioned yourself on issue #{issue.to_reference} \"Fix bug\" at #{project.namespace.owner_name} / #{project.name}")
expect(page).not_to have_content('to yourself')
end
end
@@ -176,14 +176,14 @@ describe 'Dashboard Todos' do
it 'shows you directly addressed yourself message' do
page.within('.js-todos-all') do
- expect(page).to have_content("You directly addressed yourself on issue #{issue.to_reference(full: true)}")
+ expect(page).to have_content("You directly addressed yourself on issue #{issue.to_reference} \"Fix bug\" at #{project.namespace.owner_name} / #{project.name}")
expect(page).not_to have_content('to yourself')
end
end
end
context 'approval todo' do
- let(:merge_request) { create(:merge_request) }
+ let(:merge_request) { create(:merge_request, title: "Fixes issue") }
before do
create(:todo, :approval_required, user: user, project: project, target: merge_request, author: user)
@@ -192,7 +192,7 @@ describe 'Dashboard Todos' do
it 'shows you set yourself as an approver message' do
page.within('.js-todos-all') do
- expect(page).to have_content("You set yourself as an approver for merge request #{merge_request.to_reference(full: true)}")
+ expect(page).to have_content("You set yourself as an approver for merge request #{merge_request.to_reference} \"Fixes issue\" at #{project.namespace.owner_name} / #{project.name}")
expect(page).not_to have_content('to yourself')
end
end
@@ -354,7 +354,7 @@ describe 'Dashboard Todos' do
it 'links to the pipelines for the merge request' do
href = pipelines_project_merge_request_path(project, todo.target)
- expect(page).to have_link "merge request #{todo.target.to_reference(full: true)}", href: href
+ expect(page).to have_link "merge request #{todo.target.to_reference}", href: href
end
end
end
diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb
index a090461261b..0b3f905b5de 100644
--- a/spec/features/projects/files/user_browses_files_spec.rb
+++ b/spec/features/projects/files/user_browses_files_spec.rb
@@ -14,7 +14,6 @@ describe "User browses files" do
before do
stub_feature_flags(vue_file_list: false)
- stub_feature_flags(csslab: false)
sign_in(user)
end
diff --git a/spec/finders/members_finder_spec.rb b/spec/finders/members_finder_spec.rb
index 4203f58fe81..6920fb4e572 100644
--- a/spec/finders/members_finder_spec.rb
+++ b/spec/finders/members_finder_spec.rb
@@ -17,11 +17,10 @@ describe MembersFinder, '#execute' do
result = described_class.new(project, user2).execute
- expect(result.to_a).to match_array([member1, member2, member3])
+ expect(result).to contain_exactly(member1, member2, member3)
end
- it 'includes nested group members if asked' do
- project = create(:project, namespace: group)
+ it 'includes nested group members if asked', :nested_groups do
nested_group.request_access(user1)
member1 = group.add_maintainer(user2)
member2 = nested_group.add_maintainer(user3)
@@ -29,7 +28,28 @@ describe MembersFinder, '#execute' do
result = described_class.new(project, user2).execute(include_descendants: true)
- expect(result.to_a).to match_array([member1, member2, member3])
+ expect(result).to contain_exactly(member1, member2, member3)
+ end
+
+ it 'returns the members.access_level when the user is invited', :nested_groups do
+ member_invite = create(:project_member, :invited, project: project, invite_email: create(:user).email)
+ member1 = group.add_maintainer(user2)
+
+ result = described_class.new(project, user2).execute(include_descendants: true)
+
+ expect(result).to contain_exactly(member1, member_invite)
+ expect(result.last.access_level).to eq(member_invite.access_level)
+ end
+
+ it 'returns the highest access_level for the user', :nested_groups do
+ member1 = project.add_guest(user1)
+ group.add_developer(user1)
+ nested_group.add_reporter(user1)
+
+ result = described_class.new(project, user1).execute(include_descendants: true)
+
+ expect(result).to contain_exactly(member1)
+ expect(result.first.access_level).to eq(Gitlab::Access::DEVELOPER)
end
context 'when include_invited_groups_members == true' do
@@ -37,8 +57,8 @@ describe MembersFinder, '#execute' do
set(:linked_group) { create(:group, :public, :access_requestable) }
set(:nested_linked_group) { create(:group, parent: linked_group) }
- set(:linked_group_member) { linked_group.add_developer(user1) }
- set(:nested_linked_group_member) { nested_linked_group.add_developer(user2) }
+ set(:linked_group_member) { linked_group.add_guest(user1) }
+ set(:nested_linked_group_member) { nested_linked_group.add_guest(user2) }
it 'includes all the invited_groups members including members inherited from ancestor groups' do
create(:project_group_link, project: project, group: nested_linked_group)
@@ -60,5 +80,17 @@ describe MembersFinder, '#execute' do
expect(subject).to contain_exactly(linked_group_member)
end
+
+ context 'when the user is a member of invited group and ancestor groups' do
+ it 'returns the highest access_level for the user limited by project_group_link.group_access', :nested_groups do
+ create(:project_group_link, project: project, group: nested_linked_group, group_access: Gitlab::Access::REPORTER)
+ nested_linked_group.add_developer(user1)
+
+ result = subject
+
+ expect(result).to contain_exactly(linked_group_member, nested_linked_group_member)
+ expect(result.first.access_level).to eq(Gitlab::Access::REPORTER)
+ end
+ end
end
end
diff --git a/spec/fixtures/api/schemas/entities/merge_request_noteable.json b/spec/fixtures/api/schemas/entities/merge_request_noteable.json
new file mode 100644
index 00000000000..88b0fecc24c
--- /dev/null
+++ b/spec/fixtures/api/schemas/entities/merge_request_noteable.json
@@ -0,0 +1,28 @@
+{
+ "type": "object",
+ "properties" : {
+ "merge_params": { "type": ["object", "null"] },
+ "state": { "type": "string" },
+ "source_branch": { "type": "string" },
+ "target_branch": { "type": "string" },
+ "diff_head_sha": { "type": "string" },
+ "create_note_path": { "type": ["string", "null"] },
+ "preview_note_path": { "type": ["string", "null"] },
+ "create_issue_to_resolve_discussions_path": { "type": ["string", "null"] },
+ "new_blob_path": { "type": ["string", "null"] },
+ "can_receive_suggestion": { "type": "boolean" },
+ "current_user": {
+ "type": "object",
+ "required": [
+ "can_create_note",
+ "can_update"
+ ],
+ "properties": {
+ "can_create_note": { "type": "boolean" },
+ "can_update": { "type": "boolean" }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/entities/merge_request_poll_widget.json b/spec/fixtures/api/schemas/entities/merge_request_poll_widget.json
index 2052892dfa3..1eda0e12920 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_poll_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_poll_widget.json
@@ -24,22 +24,20 @@
"ci_status": { "type": ["string", "null"] },
"cancel_auto_merge_path": { "type": ["string", "null"] },
"test_reports_path": { "type": ["string", "null"] },
- "can_receive_suggestion": { "type": "boolean" },
"create_issue_to_resolve_discussions_path": { "type": ["string", "null"] },
"current_user": {
"type": "object",
"required": [
"can_remove_source_branch",
"can_revert_on_current_merge_request",
- "can_cherry_pick_on_current_merge_request"
+ "can_cherry_pick_on_current_merge_request",
+ "can_create_issue"
],
"properties": {
"can_remove_source_branch": { "type": "boolean" },
"can_revert_on_current_merge_request": { "type": ["boolean", "null"] },
"can_cherry_pick_on_current_merge_request": { "type": ["boolean", "null"] },
- "can_create_note": { "type": "boolean" },
- "can_create_issue": { "type": "boolean" },
- "can_update": { "type": "boolean" }
+ "can_create_issue": { "type": "boolean" }
},
"additionalProperties": false
},
diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json
index 779a47222b7..e2df7952d8f 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json
@@ -5,7 +5,6 @@
{ "$ref": "merge_request_poll_widget.json" },
{
"properties" : {
- "merge_params": { "type": ["object", "null"] },
"source_project_full_path": { "type": ["string", "null"]},
"target_project_full_path": { "type": ["string", "null"]},
"email_patches_path": { "type": "string" },
@@ -13,9 +12,7 @@
"merge_request_basic_path": { "type": "string" },
"merge_request_widget_path": { "type": "string" },
"merge_request_cached_widget_path": { "type": "string" },
- "create_note_path": { "type": ["string", "null"] },
"commit_change_content_path": { "type": "string" },
- "preview_note_path": { "type": ["string", "null"] },
"conflicts_docs_path": { "type": ["string", "null"] },
"merge_request_pipelines_docs_path": { "type": ["string", "null"] },
"ci_environments_status_path": { "type": "string" },
diff --git a/spec/frontend/tracking_spec.js b/spec/frontend/tracking_spec.js
index 0e862c683d3..7c98a1a66c9 100644
--- a/spec/frontend/tracking_spec.js
+++ b/spec/frontend/tracking_spec.js
@@ -1,20 +1,56 @@
import $ from 'jquery';
import { setHTMLFixture } from './helpers/fixtures';
-import Tracking from '~/tracking';
+import Tracking, { initUserTracking } from '~/tracking';
describe('Tracking', () => {
+ let snowplowSpy;
+
beforeEach(() => {
window.snowplow = window.snowplow || (() => {});
+ window.snowplowOptions = {
+ namespace: '_namespace_',
+ hostname: 'app.gitfoo.com',
+ cookieDomain: '.gitfoo.com',
+ };
+ snowplowSpy = jest.spyOn(window, 'snowplow');
});
- describe('.event', () => {
- let snowplowSpy = null;
+ describe('initUserTracking', () => {
+ it('calls through to get a new tracker with the expected options', () => {
+ initUserTracking();
+ expect(snowplowSpy).toHaveBeenCalledWith('newTracker', '_namespace_', 'app.gitfoo.com', {
+ namespace: '_namespace_',
+ hostname: 'app.gitfoo.com',
+ cookieDomain: '.gitfoo.com',
+ appId: '',
+ userFingerprint: false,
+ respectDoNotTrack: true,
+ forceSecureTracker: true,
+ eventMethod: 'post',
+ contexts: { webPage: true },
+ activityTrackingEnabled: false,
+ pageTrackingEnabled: false,
+ });
+ });
- beforeEach(() => {
- snowplowSpy = jest.spyOn(window, 'snowplow');
+ it('should activate features based on what has been enabled', () => {
+ initUserTracking();
+ expect(snowplowSpy).not.toHaveBeenCalledWith('enableActivityTracking', 30, 30);
+ expect(snowplowSpy).not.toHaveBeenCalledWith('trackPageView');
+
+ window.snowplowOptions = Object.assign({}, window.snowplowOptions, {
+ activityTrackingEnabled: true,
+ pageTrackingEnabled: true,
+ });
+
+ initUserTracking();
+ expect(snowplowSpy).toHaveBeenCalledWith('enableActivityTracking', 30, 30);
+ expect(snowplowSpy).toHaveBeenCalledWith('trackPageView');
});
+ });
+ describe('.event', () => {
afterEach(() => {
window.doNotTrack = undefined;
navigator.doNotTrack = undefined;
diff --git a/spec/frontend/vue_shared/components/file_icon_spec.js b/spec/frontend/vue_shared/components/file_icon_spec.js
new file mode 100644
index 00000000000..328eec0a80a
--- /dev/null
+++ b/spec/frontend/vue_shared/components/file_icon_spec.js
@@ -0,0 +1,75 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLoadingIcon } from '@gitlab/ui';
+import FileIcon from '~/vue_shared/components/file_icon.vue';
+import Icon from '~/vue_shared/components/icon.vue';
+
+describe('File Icon component', () => {
+ let wrapper;
+ const findIcon = () => wrapper.find('svg');
+ const getIconName = () =>
+ findIcon()
+ .find('use')
+ .element.getAttribute('xlink:href')
+ .replace(`${gon.sprite_file_icons}#`, '');
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(FileIcon, {
+ sync: false,
+ propsData: { ...props },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should render a span element and an icon', () => {
+ createComponent({
+ fileName: 'test.js',
+ });
+
+ expect(wrapper.element.tagName).toEqual('SPAN');
+ expect(findIcon().exists()).toBeDefined();
+ });
+
+ it.each`
+ fileName | iconName
+ ${'test.js'} | ${'javascript'}
+ ${'test.png'} | ${'image'}
+ ${'webpack.js'} | ${'webpack'}
+ `('should render a $iconName icon based on file ending', ({ fileName, iconName }) => {
+ createComponent({ fileName });
+ expect(getIconName()).toBe(iconName);
+ });
+
+ it('should render a standard folder icon', () => {
+ createComponent({
+ fileName: 'js',
+ folder: true,
+ });
+
+ expect(findIcon().exists()).toBe(false);
+ expect(wrapper.find(Icon).props('cssClasses')).toContain('folder-icon');
+ });
+
+ it('should render a loading icon', () => {
+ createComponent({
+ fileName: 'test.js',
+ loading: true,
+ });
+
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ });
+
+ it('should add a special class and a size class', () => {
+ const size = 120;
+ createComponent({
+ fileName: 'test.js',
+ cssClasses: 'extraclasses',
+ size,
+ });
+
+ expect(findIcon().classes()).toContain(`s${size}`);
+ expect(findIcon().classes()).toContain('extraclasses');
+ });
+});
diff --git a/spec/javascripts/environments/environment_item_spec.js b/spec/javascripts/environments/environment_item_spec.js
index 388d7063d13..f9ee4648128 100644
--- a/spec/javascripts/environments/environment_item_spec.js
+++ b/spec/javascripts/environments/environment_item_spec.js
@@ -106,6 +106,7 @@ describe('Environment item', () => {
play_path: '/play',
},
],
+ deployed_at: '2016-11-29T18:11:58.430Z',
},
has_stop_action: true,
environment_path: 'root/ci-folders/environments/31',
@@ -139,9 +140,7 @@ describe('Environment item', () => {
it('should render last deployment date', () => {
const timeagoInstance = new timeago(); // eslint-disable-line
- const formatedDate = timeagoInstance.format(
- environment.last_deployment.deployable.created_at,
- );
+ const formatedDate = timeagoInstance.format(environment.last_deployment.deployed_at);
expect(
component.$el.querySelector('.environment-created-date-timeago').textContent,
diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js
index 5f81a168498..3812d46f838 100644
--- a/spec/javascripts/notes/mock_data.js
+++ b/spec/javascripts/notes/mock_data.js
@@ -8,7 +8,7 @@ export const notesDataMock = {
notesPath: '/gitlab-org/gitlab-ce/noteable/issue/98/notes',
quickActionsDocsPath: '/help/user/project/quick_actions',
registerPath: '/users/sign_in?redirect_to_referer=yes#register-pane',
- totalNotes: 1,
+ prerenderedNotesCount: 1,
closePath: '/twitter/flight/issues/9.json?issue%5Bstate_event%5D=close',
reopenPath: '/twitter/flight/issues/9.json?issue%5Bstate_event%5D=reopen',
canAwardEmoji: true,
diff --git a/spec/javascripts/vue_shared/components/file_icon_spec.js b/spec/javascripts/vue_shared/components/file_icon_spec.js
deleted file mode 100644
index 1f61e19fa84..00000000000
--- a/spec/javascripts/vue_shared/components/file_icon_spec.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import Vue from 'vue';
-import fileIcon from '~/vue_shared/components/file_icon.vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-
-describe('File Icon component', () => {
- let vm;
- let FileIcon;
-
- beforeEach(() => {
- FileIcon = Vue.extend(fileIcon);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('should render a span element with an svg', () => {
- vm = mountComponent(FileIcon, {
- fileName: 'test.js',
- });
-
- expect(vm.$el.tagName).toEqual('SPAN');
- expect(vm.$el.querySelector('span > svg')).toBeDefined();
- });
-
- it('should render a javascript icon based on file ending', () => {
- vm = mountComponent(FileIcon, {
- fileName: 'test.js',
- });
-
- expect(vm.$el.firstChild.firstChild.getAttribute('xlink:href')).toBe(
- `${gon.sprite_file_icons}#javascript`,
- );
- });
-
- it('should render a image icon based on file ending', () => {
- vm = mountComponent(FileIcon, {
- fileName: 'test.png',
- });
-
- expect(vm.$el.firstChild.firstChild.getAttribute('xlink:href')).toBe(
- `${gon.sprite_file_icons}#image`,
- );
- });
-
- it('should render a webpack icon based on file namer', () => {
- vm = mountComponent(FileIcon, {
- fileName: 'webpack.js',
- });
-
- expect(vm.$el.firstChild.firstChild.getAttribute('xlink:href')).toBe(
- `${gon.sprite_file_icons}#webpack`,
- );
- });
-
- it('should render a standard folder icon', () => {
- vm = mountComponent(FileIcon, {
- fileName: 'js',
- folder: true,
- });
-
- expect(vm.$el.querySelector('span > svg > use').getAttribute('xlink:href')).toBe(
- `${gon.sprite_file_icons}#folder`,
- );
- });
-
- it('should render a loading icon', () => {
- vm = mountComponent(FileIcon, {
- fileName: 'test.js',
- loading: true,
- });
-
- const { classList } = vm.$el.querySelector('.loading-container span');
-
- expect(classList.contains('gl-spinner')).toEqual(true);
- });
-
- it('should add a special class and a size class', () => {
- vm = mountComponent(FileIcon, {
- fileName: 'test.js',
- cssClasses: 'extraclasses',
- size: 120,
- });
-
- const { classList } = vm.$el.firstChild;
- const containsSizeClass = classList.contains('s120');
- const containsCustomClass = classList.contains('extraclasses');
-
- expect(containsSizeClass).toBe(true);
- expect(containsCustomClass).toBe(true);
- });
-});
diff --git a/spec/lib/gitlab/danger/teammate_spec.rb b/spec/lib/gitlab/danger/teammate_spec.rb
index 61b43e343c1..afbc3896a70 100644
--- a/spec/lib/gitlab/danger/teammate_spec.rb
+++ b/spec/lib/gitlab/danger/teammate_spec.rb
@@ -50,6 +50,14 @@ describe Gitlab::Danger::Teammate do
end
end
+ context 'when role is Test Automation Engineer' do
+ let(:role) { 'Test Automation Engineer' }
+
+ it '#reviewer? returns false' do
+ expect(subject.reviewer?(project, :test, labels)).to be_falsey
+ end
+ end
+
context 'when role is Test Automation Engineer, Manage' do
let(:role) { 'Test Automation Engineer, Manage' }
diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
index 4d2f08f95fc..790b0428d19 100644
--- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
@@ -102,6 +102,23 @@ describe Gitlab::Gfm::ReferenceRewriter do
end
end
+ context 'with a commit' do
+ let(:old_project) { create(:project, :repository, name: 'old-project', group: group) }
+ let(:commit) { old_project.commit }
+
+ context 'reference to an absolute URL to a commit' do
+ let(:text) { Gitlab::UrlBuilder.build(commit) }
+
+ it { is_expected.to eq(text) }
+ end
+
+ context 'reference to a commit' do
+ let(:text) { commit.id }
+
+ it { is_expected.to eq("#{old_project_ref}@#{text}") }
+ end
+ end
+
context 'reference contains project milestone' do
let!(:milestone) do
create(:milestone, title: '9.0', project: old_project)
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 3c6b17c10ec..ec4a6ef05b9 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -483,3 +483,4 @@ lists:
- milestone
- board
- label
+- list_user_preferences
diff --git a/spec/lib/gitlab/performance_bar/with_top_level_warnings_spec.rb b/spec/lib/gitlab/performance_bar/with_top_level_warnings_spec.rb
new file mode 100644
index 00000000000..3b92261f0fe
--- /dev/null
+++ b/spec/lib/gitlab/performance_bar/with_top_level_warnings_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+describe Gitlab::PerformanceBar::WithTopLevelWarnings do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { Module.new }
+
+ before do
+ subject.singleton_class.prepend(described_class)
+ end
+
+ describe '#has_warnings?' do
+ where(:has_warnings, :results) do
+ false | { data: {} }
+ false | { data: { gitaly: { warnings: [] } } }
+ true | { data: { gitaly: { warnings: [1] } } }
+ true | { data: { gitaly: { warnings: [] }, redis: { warnings: [1] } } }
+ end
+
+ with_them do
+ it do
+ expect(subject.has_warnings?(results)).to eq(has_warnings)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/snowplow_tracker_spec.rb b/spec/lib/gitlab/snowplow_tracker_spec.rb
deleted file mode 100644
index 073a33e5973..00000000000
--- a/spec/lib/gitlab/snowplow_tracker_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-describe Gitlab::SnowplowTracker do
- let(:timestamp) { Time.utc(2017, 3, 22) }
-
- around do |example|
- Timecop.freeze(timestamp) { example.run }
- end
-
- subject { described_class.track_event('epics', 'action', property: 'what', value: 'doit') }
-
- context '.track_event' do
- context 'when Snowplow tracker is disabled' do
- it 'does not track the event' do
- expect(SnowplowTracker::Tracker).not_to receive(:new)
-
- subject
- end
- end
-
- context 'when Snowplow tracker is enabled' do
- before do
- stub_application_setting(snowplow_enabled: true)
- stub_application_setting(snowplow_site_id: 'awesome gitlab')
- stub_application_setting(snowplow_collector_hostname: 'url.com')
- end
-
- it 'tracks the event' do
- tracker = double
-
- expect(::SnowplowTracker::Tracker).to receive(:new)
- .with(
- an_instance_of(::SnowplowTracker::Emitter),
- an_instance_of(::SnowplowTracker::Subject),
- 'cf', 'awesome gitlab'
- ).and_return(tracker)
- expect(tracker).to receive(:track_struct_event)
- .with('epics', 'action', nil, 'what', 'doit', nil, timestamp.to_i)
-
- subject
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb
new file mode 100644
index 00000000000..f14e74427e1
--- /dev/null
+++ b/spec/lib/gitlab/tracking_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+describe Gitlab::Tracking do
+ let(:timestamp) { Time.utc(2017, 3, 22) }
+
+ before do
+ stub_application_setting(snowplow_enabled: true)
+ stub_application_setting(snowplow_collector_hostname: 'gitfoo.com')
+ stub_application_setting(snowplow_cookie_domain: '.gitfoo.com')
+ stub_application_setting(snowplow_site_id: '_abc123_')
+ end
+
+ describe '.snowplow_options' do
+ subject(&method(:described_class))
+
+ it 'returns useful client options' do
+ expect(subject.snowplow_options(nil)).to eq(
+ namespace: 'gl',
+ hostname: 'gitfoo.com',
+ cookieDomain: '.gitfoo.com',
+ appId: '_abc123_',
+ pageTrackingEnabled: true,
+ activityTrackingEnabled: true
+ )
+ end
+
+ it 'enables features using feature flags' do
+ stub_feature_flags(additional_snowplow_tracking: true)
+ allow(Feature).to receive(:enabled?).with(
+ :additional_snowplow_tracking,
+ '_group_'
+ ).and_return(false)
+
+ expect(subject.snowplow_options('_group_')).to include(
+ pageTrackingEnabled: false,
+ activityTrackingEnabled: false
+ )
+ end
+ end
+
+ describe '.event' do
+ subject(&method(:described_class))
+
+ around do |example|
+ Timecop.freeze(timestamp) { example.run }
+ end
+
+ it 'can track events' do
+ tracker = double
+
+ expect(SnowplowTracker::Emitter).to receive(:new).with(
+ 'gitfoo.com'
+ ).and_return('_emitter_')
+
+ expect(SnowplowTracker::Tracker).to receive(:new).with(
+ '_emitter_',
+ an_instance_of(SnowplowTracker::Subject),
+ 'gl',
+ '_abc123_'
+ ).and_return(tracker)
+
+ expect(tracker).to receive(:track_struct_event).with(
+ 'category',
+ 'action',
+ '_label_',
+ '_property_',
+ '_value_',
+ '_context_',
+ timestamp.to_i
+ )
+
+ subject.event('category', 'action',
+ label: '_label_',
+ property: '_property_',
+ value: '_value_',
+ context: '_context_'
+ )
+ end
+
+ it 'does not track when not enabled' do
+ stub_application_setting(snowplow_enabled: false)
+ expect(SnowplowTracker::Tracker).not_to receive(:new)
+
+ subject.event('epics', 'action', property: 'what', value: 'doit')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 5c5ff46112f..98421cd12d3 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -14,6 +14,12 @@ describe Gitlab::Workhorse do
[key, command, params]
end
+ before do
+ allow(Feature::Gitaly).to receive(:server_feature_flags).and_return({
+ 'gitaly-feature-foobar' => 'true'
+ })
+ end
+
describe ".send_git_archive" do
let(:ref) { 'master' }
let(:format) { 'zip' }
@@ -41,6 +47,7 @@ describe Gitlab::Workhorse do
expected_params = metadata.merge(
'GitalyRepository' => repository.gitaly_repository.to_h,
'GitalyServer' => {
+ features: { 'gitaly-feature-foobar' => 'true' },
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
}
@@ -69,6 +76,7 @@ describe Gitlab::Workhorse do
expect(command).to eq('git-archive')
expect(params).to eq({
'GitalyServer' => {
+ features: { 'gitaly-feature-foobar' => 'true' },
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
},
@@ -117,6 +125,7 @@ describe Gitlab::Workhorse do
expect(command).to eq("git-format-patch")
expect(params).to eq({
'GitalyServer' => {
+ features: { 'gitaly-feature-foobar' => 'true' },
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
},
@@ -178,6 +187,7 @@ describe Gitlab::Workhorse do
expect(command).to eq("git-diff")
expect(params).to eq({
'GitalyServer' => {
+ features: { 'gitaly-feature-foobar' => 'true' },
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
},
@@ -315,6 +325,7 @@ describe Gitlab::Workhorse do
let(:gitaly_params) do
{
GitalyServer: {
+ features: { 'gitaly-feature-foobar' => 'true' },
address: Gitlab::GitalyClient.address('default'),
token: Gitlab::GitalyClient.token('default')
}
@@ -463,6 +474,7 @@ describe Gitlab::Workhorse do
expect(command).to eq('git-blob')
expect(params).to eq({
'GitalyServer' => {
+ features: { 'gitaly-feature-foobar' => 'true' },
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
},
@@ -504,6 +516,7 @@ describe Gitlab::Workhorse do
expect(command).to eq('git-snapshot')
expect(params).to eq(
'GitalyServer' => {
+ 'features' => { 'gitaly-feature-foobar' => 'true' },
'address' => Gitlab::GitalyClient.address(project.repository_storage),
'token' => Gitlab::GitalyClient.token(project.repository_storage)
},
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index cbc5649fc09..1fc363460ae 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -98,6 +98,33 @@ describe Gitlab do
end
end
+ describe '.dev_env_org_or_com?' do
+ it 'is true when on .com' do
+ allow(described_class).to receive_messages(com?: true, org?: false)
+
+ expect(described_class.dev_env_org_or_com?).to eq true
+ end
+
+ it 'is true when org' do
+ allow(described_class).to receive_messages(com?: false, org?: true)
+
+ expect(described_class.dev_env_org_or_com?).to eq true
+ end
+
+ it 'is true when dev env' do
+ allow(described_class).to receive_messages(com?: false, org?: false)
+ allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development'))
+
+ expect(described_class.dev_env_org_or_com?).to eq true
+ end
+
+ it 'is false when not dev, org or com' do
+ allow(described_class).to receive_messages(com?: false, org?: false)
+
+ expect(described_class.dev_env_org_or_com?).to eq false
+ end
+ end
+
describe '.ee?' do
before do
described_class.instance_variable_set(:@is_ee, nil)
diff --git a/spec/lib/peek/views/detailed_view_spec.rb b/spec/lib/peek/views/detailed_view_spec.rb
new file mode 100644
index 00000000000..d8660a55ea9
--- /dev/null
+++ b/spec/lib/peek/views/detailed_view_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+describe Peek::Views::DetailedView, :request_store do
+ context 'when a class defines thresholds' do
+ let(:threshold_view) do
+ Class.new(described_class) do
+ def self.thresholds
+ {
+ calls: 1,
+ duration: 10,
+ individual_call: 5
+ }
+ end
+
+ def key
+ 'threshold-view'
+ end
+ end.new
+ end
+
+ context 'when the results exceed the calls threshold' do
+ before do
+ allow(threshold_view)
+ .to receive(:detail_store).and_return([{ duration: 0.001 }, { duration: 0.001 }])
+ end
+
+ it 'adds a warning to the results key' do
+ expect(threshold_view.results).to include(warnings: [a_string_matching('threshold-view calls')])
+ end
+ end
+
+ context 'when the results exceed the duration threshold' do
+ before do
+ allow(threshold_view)
+ .to receive(:detail_store).and_return([{ duration: 0.011 }])
+ end
+
+ it 'adds a warning to the results key' do
+ expect(threshold_view.results).to include(warnings: [a_string_matching('threshold-view duration')])
+ end
+ end
+
+ context 'when a single call exceeds the duration threshold' do
+ before do
+ allow(threshold_view)
+ .to receive(:detail_store).and_return([{ duration: 0.001 }, { duration: 0.006 }])
+ end
+
+ it 'adds a warning to that call detail entry' do
+ expect(threshold_view.results)
+ .to include(details: a_collection_containing_exactly(
+ { duration: 1.0, warnings: [] },
+ { duration: 6.0, warnings: ['6.0 over 5'] }
+ ))
+ end
+ end
+ end
+
+ context 'when a view does not define thresholds' do
+ let(:no_threshold_view) { Class.new(described_class).new }
+
+ before do
+ allow(no_threshold_view)
+ .to receive(:detail_store).and_return([{ duration: 100 }, { duration: 100 }])
+ end
+
+ it 'does not add warnings to the top level' do
+ expect(no_threshold_view.results).to include(warnings: [])
+ end
+
+ it 'does not add warnings to call details entries' do
+ expect(no_threshold_view.results)
+ .to include(details: a_collection_containing_exactly(
+ { duration: 100000, warnings: [] },
+ { duration: 100000, warnings: [] }
+ ))
+ end
+ end
+end
diff --git a/spec/lib/peek/views/redis_detailed_spec.rb b/spec/lib/peek/views/redis_detailed_spec.rb
index 61096e6c69e..fa9532226f2 100644
--- a/spec/lib/peek/views/redis_detailed_spec.rb
+++ b/spec/lib/peek/views/redis_detailed_spec.rb
@@ -21,10 +21,10 @@ describe Peek::Views::RedisDetailed, :request_store do
expect(subject.results[:details].count).to eq(1)
expect(subject.results[:details].first)
- .to eq({
- cmd: expected,
- duration: 1000
- })
+ .to include({
+ cmd: expected,
+ duration: 1000
+ })
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 7b35c2ffd36..5ef824b9950 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -192,6 +192,24 @@ describe Commit do
end
end
+ describe '.reference_valid?' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:ref, :result) do
+ '1234567' | true
+ '123456' | false
+ '1' | false
+ '0' * 40 | true
+ 'c1acaa58bbcbc3eafe538cb8274ba387047b69f8' | true
+ 'H1acaa58bbcbc3eafe538cb8274ba387047b69f8' | false
+ nil | false
+ end
+
+ with_them do
+ it { expect(described_class.reference_valid?(ref)).to eq(result) }
+ end
+ end
+
describe '#reference_link_text' do
let(:project) { create(:project, :repository, path: 'sample-project') }
diff --git a/spec/models/concerns/noteable_spec.rb b/spec/models/concerns/noteable_spec.rb
index e17b98536fa..929b5f52c7c 100644
--- a/spec/models/concerns/noteable_spec.rb
+++ b/spec/models/concerns/noteable_spec.rb
@@ -272,4 +272,22 @@ describe Noteable do
expect(described_class.resolvable_types).to include('MergeRequest')
end
end
+
+ describe '#capped_notes_count' do
+ context 'notes number < 10' do
+ it 'the number of notes is returned' do
+ expect(subject.capped_notes_count(10)).to eq(9)
+ end
+ end
+
+ context 'notes number > 10' do
+ before do
+ create_list(:note, 2, project: project, noteable: subject)
+ end
+
+ it '10 is returned' do
+ expect(subject.capped_notes_count(10)).to eq(10)
+ end
+ end
+ end
end
diff --git a/spec/models/list_spec.rb b/spec/models/list_spec.rb
index 18d4549977c..2429cd408a6 100644
--- a/spec/models/list_spec.rb
+++ b/spec/models/list_spec.rb
@@ -81,4 +81,83 @@ describe List do
expect(subject.title).to eq 'Closed'
end
end
+
+ describe '#update_preferences_for' do
+ let(:user) { create(:user) }
+ let(:list) { create(:list) }
+
+ context 'when user is present' do
+ context 'when there are no preferences for user' do
+ it 'creates new user preferences' do
+ expect { list.update_preferences_for(user, collapsed: true) }.to change { ListUserPreference.count }.by(1)
+ expect(list.preferences_for(user).collapsed).to eq(true)
+ end
+ end
+
+ context 'when there are preferences for user' do
+ it 'updates user preferences' do
+ list.update_preferences_for(user, collapsed: false)
+
+ expect { list.update_preferences_for(user, collapsed: true) }.not_to change { ListUserPreference.count }
+ expect(list.preferences_for(user).collapsed).to eq(true)
+ end
+ end
+
+ context 'when user is nil' do
+ it 'does not create user preferences' do
+ expect { list.update_preferences_for(nil, collapsed: true) }.not_to change { ListUserPreference.count }
+ end
+ end
+ end
+ end
+
+ describe '#preferences_for' do
+ let(:user) { create(:user) }
+ let(:list) { create(:list) }
+
+ context 'when user is nil' do
+ it 'returns not persisted preferences' do
+ preferences = list.preferences_for(nil)
+
+ expect(preferences.persisted?).to eq(false)
+ expect(preferences.list_id).to eq(list.id)
+ expect(preferences.user_id).to be_nil
+ end
+ end
+
+ context 'when a user preference already exists' do
+ before do
+ list.update_preferences_for(user, collapsed: true)
+ end
+
+ it 'loads preference for user' do
+ preferences = list.preferences_for(user)
+
+ expect(preferences).to be_persisted
+ expect(preferences.collapsed).to eq(true)
+ end
+
+ context 'when preferences are already loaded for user' do
+ it 'gets preloaded user preferences' do
+ fetched_list = described_class.where(id: list.id).with_preferences_for(user).first
+
+ expect(fetched_list).to receive(:preloaded_preferences_for).with(user).and_call_original
+
+ preferences = fetched_list.preferences_for(user)
+
+ expect(preferences.collapsed).to eq(true)
+ end
+ end
+ end
+
+ context 'when preferences for user does not exist' do
+ it 'returns not persisted preferences' do
+ preferences = list.preferences_for(user)
+
+ expect(preferences.persisted?).to eq(false)
+ expect(preferences.user_id).to eq(user.id)
+ expect(preferences.list_id).to eq(list.id)
+ end
+ end
+ end
end
diff --git a/spec/models/list_user_preference_spec.rb b/spec/models/list_user_preference_spec.rb
new file mode 100644
index 00000000000..1335a3700dc
--- /dev/null
+++ b/spec/models/list_user_preference_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ListUserPreference do
+ set(:user) { create(:user) }
+ set(:list) { create(:list) }
+
+ before do
+ list.update_preferences_for(user, { collapsed: true })
+ end
+
+ describe 'relationships' do
+ it { is_expected.to belong_to(:list) }
+ it { is_expected.to belong_to(:user) }
+
+ it do
+ is_expected.to validate_uniqueness_of(:user_id).scoped_to(:list_id)
+ .with_message("should have only one list preference per user")
+ end
+ end
+end
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index 9aeef7c3b4b..ce17704acbd 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -121,12 +121,12 @@ describe Todo do
subject.target_type = 'Commit'
subject.commit_id = commit.id
- expect(subject.target_reference).to eq commit.reference_link_text(full: true)
+ expect(subject.target_reference).to eq commit.reference_link_text(full: false)
end
it 'returns full reference for issuables' do
subject.target = issue
- expect(subject.target_reference).to eq issue.to_reference(full: true)
+ expect(subject.target_reference).to eq issue.to_reference(full: false)
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 8338d2b5b39..f1408194250 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1176,7 +1176,7 @@ describe User do
expect(user.can_create_group).to eq(Gitlab.config.gitlab.default_can_create_group)
expect(user.theme_id).to eq(Gitlab.config.gitlab.default_theme)
expect(user.external).to be_falsey
- expect(user.private_profile).to eq false
+ expect(user.private_profile).to eq(false)
end
end
diff --git a/spec/requests/api/project_snapshots_spec.rb b/spec/requests/api/project_snapshots_spec.rb
index 44b5ee1f130..2857715cdbe 100644
--- a/spec/requests/api/project_snapshots_spec.rb
+++ b/spec/requests/api/project_snapshots_spec.rb
@@ -6,6 +6,12 @@ describe API::ProjectSnapshots do
let(:project) { create(:project) }
let(:admin) { create(:admin) }
+ before do
+ allow(Feature::Gitaly).to receive(:server_feature_flags).and_return({
+ 'gitaly-feature-foobar' => 'true'
+ })
+ end
+
describe 'GET /projects/:id/snapshot' do
def expect_snapshot_response_for(repository)
type, params = workhorse_send_data
@@ -13,6 +19,7 @@ describe API::ProjectSnapshots do
expect(type).to eq('git-snapshot')
expect(params).to eq(
'GitalyServer' => {
+ 'features' => { 'gitaly-feature-foobar' => 'true' },
'address' => Gitlab::GitalyClient.address(repository.project.repository_storage),
'token' => Gitlab::GitalyClient.token(repository.project.repository_storage)
},
diff --git a/spec/rubocop/cop/rspec/be_success_matcher_spec.rb b/spec/rubocop/cop/rspec/be_success_matcher_spec.rb
new file mode 100644
index 00000000000..12aa7d1643e
--- /dev/null
+++ b/spec/rubocop/cop/rspec/be_success_matcher_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_relative '../../../../rubocop/cop/rspec/be_success_matcher'
+
+describe RuboCop::Cop::RSpec::BeSuccessMatcher do
+ include CopHelper
+
+ let(:source_file) { 'spec/foo_spec.rb' }
+
+ subject(:cop) { described_class.new }
+
+ shared_examples 'cop' do |good:, bad:|
+ context "using #{bad} call" do
+ it 'registers an offense' do
+ inspect_source(bad, source_file)
+
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ expect(cop.highlights).to eq([bad])
+ end
+
+ it "autocorrects it to `#{good}`" do
+ autocorrected = autocorrect_source(bad, source_file)
+
+ expect(autocorrected).to eql(good)
+ end
+ end
+
+ context "using #{good} call" do
+ it 'does not register an offense' do
+ inspect_source(good)
+
+ expect(cop.offenses).to be_empty
+ end
+ end
+ end
+
+ include_examples 'cop',
+ bad: 'expect(response).to be_success',
+ good: 'expect(response).to be_successful'
+
+ include_examples 'cop',
+ bad: 'expect(response).to_not be_success',
+ good: 'expect(response).to_not be_successful'
+
+ include_examples 'cop',
+ bad: 'expect(response).not_to be_success',
+ good: 'expect(response).not_to be_successful'
+
+ include_examples 'cop',
+ bad: 'is_expected.to be_success',
+ good: 'is_expected.to be_successful'
+
+ include_examples 'cop',
+ bad: 'is_expected.to_not be_success',
+ good: 'is_expected.to_not be_successful'
+
+ include_examples 'cop',
+ bad: 'is_expected.not_to be_success',
+ good: 'is_expected.not_to be_successful'
+end
diff --git a/spec/serializers/merge_request_serializer_spec.rb b/spec/serializers/merge_request_serializer_spec.rb
index 276e0f6ff3d..d1483c3c41e 100644
--- a/spec/serializers/merge_request_serializer_spec.rb
+++ b/spec/serializers/merge_request_serializer_spec.rb
@@ -41,6 +41,14 @@ describe MergeRequestSerializer do
end
end
+ context 'noteable merge request serialization' do
+ let(:serializer) { 'noteable' }
+
+ it 'matches noteable merge request json schema' do
+ expect(json_entity).to match_schema('entities/merge_request_noteable', strict: true)
+ end
+ end
+
context 'no serializer' do
let(:serializer) { nil }
diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb
index 2ebfd295fa2..2535f339495 100644
--- a/spec/services/boards/lists/list_service_spec.rb
+++ b/spec/services/boards/lists/list_service_spec.rb
@@ -3,13 +3,15 @@
require 'spec_helper'
describe Boards::Lists::ListService do
+ let(:user) { create(:user) }
+
describe '#execute' do
context 'when board parent is a project' do
let(:project) { create(:project) }
let(:board) { create(:board, project: project) }
let(:label) { create(:label, project: project) }
let!(:list) { create(:list, board: board, label: label) }
- let(:service) { described_class.new(project, double) }
+ let(:service) { described_class.new(project, user) }
it_behaves_like 'lists list service'
end
@@ -19,7 +21,7 @@ describe Boards::Lists::ListService do
let(:board) { create(:board, group: group) }
let(:label) { create(:group_label, group: group) }
let!(:list) { create(:list, board: board, label: label) }
- let(:service) { described_class.new(group, double) }
+ let(:service) { described_class.new(group, user) }
it_behaves_like 'lists list service'
end
diff --git a/spec/services/boards/lists/update_service_spec.rb b/spec/services/boards/lists/update_service_spec.rb
new file mode 100644
index 00000000000..f28bbab941a
--- /dev/null
+++ b/spec/services/boards/lists/update_service_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Boards::Lists::UpdateService do
+ let(:user) { create(:user) }
+ let!(:list) { create(:list, board: board, position: 0) }
+
+ shared_examples 'moving list' do
+ context 'when user can admin list' do
+ it 'calls Lists::MoveService to update list position' do
+ board.parent.add_developer(user)
+ service = described_class.new(board.parent, user, position: 1)
+
+ expect(Boards::Lists::MoveService).to receive(:new).with(board.parent, user, { position: 1 }).and_call_original
+ expect_any_instance_of(Boards::Lists::MoveService).to receive(:execute).with(list)
+
+ service.execute(list)
+ end
+ end
+
+ context 'when user cannot admin list' do
+ it 'does not call Lists::MoveService to update list position' do
+ service = described_class.new(board.parent, user, position: 1)
+
+ expect(Boards::Lists::MoveService).not_to receive(:new)
+
+ service.execute(list)
+ end
+ end
+ end
+
+ shared_examples 'updating list preferences' do
+ context 'when user can read list' do
+ it 'updates list preference for user' do
+ board.parent.add_guest(user)
+ service = described_class.new(board.parent, user, collapsed: true)
+
+ service.execute(list)
+
+ expect(list.preferences_for(user).collapsed).to eq(true)
+ end
+ end
+
+ context 'when user cannot read list' do
+ it 'does not update list preference for user' do
+ service = described_class.new(board.parent, user, collapsed: true)
+
+ service.execute(list)
+
+ expect(list.preferences_for(user).collapsed).to be_nil
+ end
+ end
+ end
+
+ describe '#execute' do
+ context 'when position parameter is present' do
+ context 'for projects' do
+ it_behaves_like 'moving list' do
+ let(:project) { create(:project, :private) }
+ let(:board) { create(:board, project: project) }
+ end
+ end
+
+ context 'for groups' do
+ it_behaves_like 'moving list' do
+ let(:group) { create(:group, :private) }
+ let(:board) { create(:board, group: group) }
+ end
+ end
+ end
+
+ context 'when collapsed parameter is present' do
+ context 'for projects' do
+ it_behaves_like 'updating list preferences' do
+ let(:project) { create(:project, :private) }
+ let(:board) { create(:board, project: project) }
+ end
+ end
+
+ context 'for groups' do
+ it_behaves_like 'updating list preferences' do
+ let(:group) { create(:group, :private) }
+ let(:board) { create(:board, group: group) }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/projects/forks_count_service_spec.rb b/spec/services/projects/forks_count_service_spec.rb
index 7e35648e9ff..1b44782468a 100644
--- a/spec/services/projects/forks_count_service_spec.rb
+++ b/spec/services/projects/forks_count_service_spec.rb
@@ -2,15 +2,17 @@
require 'spec_helper'
-describe Projects::ForksCountService do
+describe Projects::ForksCountService, :use_clean_rails_memory_store_caching do
+ let(:project) { build(:project) }
+ subject { described_class.new(project) }
+
+ it_behaves_like 'a counter caching service'
+
describe '#count' do
it 'returns the number of forks' do
- project = build(:project, id: 42)
- service = described_class.new(project)
-
- allow(service).to receive(:uncached_count).and_return(1)
+ allow(subject).to receive(:uncached_count).and_return(1)
- expect(service.count).to eq(1)
+ expect(subject.count).to eq(1)
end
end
end
diff --git a/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb
index 849601c4a63..66233787d3a 100644
--- a/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb
@@ -30,5 +30,23 @@ describe Projects::LfsPointers::LfsLinkService do
expect(subject.execute(new_oid_list.keys)).to eq linked
end
+
+ it 'links in batches' do
+ stub_const("#{described_class}::BATCH_SIZE", 3)
+
+ expect(Gitlab::Import::Logger)
+ .to receive(:info)
+ .with(class: described_class.name,
+ project_id: project.id,
+ project_path: project.full_path,
+ lfs_objects_linked_count: 7,
+ iterations: 3)
+
+ lfs_objects = create_list(:lfs_object, 7)
+ linked = subject.execute(lfs_objects.pluck(:oid))
+
+ expect(project.all_lfs_objects.count).to eq 9
+ expect(linked.size).to eq 7
+ end
end
end
diff --git a/spec/services/projects/open_issues_count_service_spec.rb b/spec/services/projects/open_issues_count_service_spec.rb
index 8efa34765d0..593a4df1f8f 100644
--- a/spec/services/projects/open_issues_count_service_spec.rb
+++ b/spec/services/projects/open_issues_count_service_spec.rb
@@ -2,10 +2,13 @@
require 'spec_helper'
-describe Projects::OpenIssuesCountService do
- describe '#count' do
- let(:project) { create(:project) }
+describe Projects::OpenIssuesCountService, :use_clean_rails_memory_store_caching do
+ let(:project) { create(:project) }
+ subject { described_class.new(project) }
+
+ it_behaves_like 'a counter caching service'
+ describe '#count' do
context 'when user is nil' do
it 'does not include confidential issues in the issue count' do
create(:issue, :opened, project: project)
@@ -53,9 +56,7 @@ describe Projects::OpenIssuesCountService do
end
end
- context '#refresh_cache', :use_clean_rails_memory_store_caching do
- let(:subject) { described_class.new(project) }
-
+ context '#refresh_cache' do
before do
create(:issue, :opened, project: project)
create(:issue, :opened, project: project)
diff --git a/spec/services/projects/open_merge_requests_count_service_spec.rb b/spec/services/projects/open_merge_requests_count_service_spec.rb
index 0d8227f7db5..f9fff4cbd4c 100644
--- a/spec/services/projects/open_merge_requests_count_service_spec.rb
+++ b/spec/services/projects/open_merge_requests_count_service_spec.rb
@@ -2,16 +2,21 @@
require 'spec_helper'
-describe Projects::OpenMergeRequestsCountService do
+describe Projects::OpenMergeRequestsCountService, :use_clean_rails_memory_store_caching do
+ set(:project) { create(:project) }
+
+ subject { described_class.new(project) }
+
+ it_behaves_like 'a counter caching service'
+
describe '#count' do
it 'returns the number of open merge requests' do
- project = create(:project)
create(:merge_request,
:opened,
source_project: project,
target_project: project)
- expect(described_class.new(project).count).to eq(1)
+ expect(subject.count).to eq(1)
end
end
end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index f46f9633c1c..910fe3b50b7 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -212,6 +212,13 @@ describe SystemNoteService do
expect(build_note([assignee, assignee1, assignee2], [assignee, assignee1])).to eq \
"unassigned @#{assignee2.username}"
end
+
+ it 'builds a correct phrase when the locale is different' do
+ Gitlab::I18n.with_locale('pt-BR') do
+ expect(build_note([assignee, assignee1, assignee2], [assignee3])).to eq \
+ "assigned to @#{assignee3.username} and unassigned @#{assignee.username}, @#{assignee1.username}, and @#{assignee2.username}"
+ end
+ end
end
describe '.change_milestone' do
diff --git a/spec/services/users/keys_count_service_spec.rb b/spec/services/users/keys_count_service_spec.rb
index bee8380e8b7..6b7493f343f 100644
--- a/spec/services/users/keys_count_service_spec.rb
+++ b/spec/services/users/keys_count_service_spec.rb
@@ -4,7 +4,9 @@ require 'spec_helper'
describe Users::KeysCountService, :use_clean_rails_memory_store_caching do
let(:user) { create(:user) }
- let(:service) { described_class.new(user) }
+ subject { described_class.new(user) }
+
+ it_behaves_like 'a counter caching service'
describe '#count' do
before do
@@ -12,53 +14,19 @@ describe Users::KeysCountService, :use_clean_rails_memory_store_caching do
end
it 'returns the number of SSH keys as an Integer' do
- expect(service.count).to eq(1)
- end
-
- it 'caches the number of keys in Redis', :request_store do
- service.delete_cache
- control_count = ActiveRecord::QueryRecorder.new { service.count }.count
- service.delete_cache
-
- expect { 2.times { service.count } }.not_to exceed_query_limit(control_count)
- end
- end
-
- describe '#refresh_cache' do
- it 'refreshes the Redis cache' do
- Rails.cache.write(service.cache_key, 10)
- service.refresh_cache
-
- expect(Rails.cache.fetch(service.cache_key, raw: true)).to be_zero
- end
- end
-
- describe '#delete_cache' do
- it 'removes the cache' do
- service.count
- service.delete_cache
-
- expect(Rails.cache.fetch(service.cache_key, raw: true)).to be_nil
+ expect(subject.count).to eq(1)
end
end
describe '#uncached_count' do
it 'returns the number of SSH keys' do
- expect(service.uncached_count).to be_zero
- end
-
- it 'does not cache the number of keys' do
- recorder = ActiveRecord::QueryRecorder.new do
- 2.times { service.uncached_count }
- end
-
- expect(recorder.count).to be > 0
+ expect(subject.uncached_count).to be_zero
end
end
describe '#cache_key' do
it 'returns the cache key' do
- expect(service.cache_key).to eq("users/key-count-service/#{user.id}")
+ expect(subject.cache_key).to eq("users/key-count-service/#{user.id}")
end
end
end
diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb
index d936dc6de41..9d47a0c23df 100644
--- a/spec/support/helpers/query_recorder.rb
+++ b/spec/support/helpers/query_recorder.rb
@@ -8,7 +8,10 @@ module ActiveRecord
@log = []
@cached = []
@skip_cached = skip_cached
- ActiveSupport::Notifications.subscribed(method(:callback), 'sql.active_record', &block)
+ # force replacement of bind parameters to give tests the ability to check for ids
+ ActiveRecord::Base.connection.unprepared_statement do
+ ActiveSupport::Notifications.subscribed(method(:callback), 'sql.active_record', &block)
+ end
end
def show_backtrace(values)
diff --git a/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb
index 38f6011646e..e7fee7239fc 100644
--- a/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb
+++ b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb
@@ -6,9 +6,10 @@ RSpec.shared_context 'GroupProjectsFinder context' do
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
let(:current_user) { create(:user) }
+ let(:params) { {} }
let(:options) { {} }
- let(:finder) { described_class.new(group: group, current_user: current_user, options: options) }
+ let(:finder) { described_class.new(group: group, current_user: current_user, params: params, options: options) }
let!(:public_project) { create(:project, :public, group: group, path: '1') }
let!(:private_project) { create(:project, :private, group: group, path: '2') }
diff --git a/spec/support/shared_examples/services/count_service_shared_examples.rb b/spec/support/shared_examples/services/count_service_shared_examples.rb
new file mode 100644
index 00000000000..9bea180a778
--- /dev/null
+++ b/spec/support/shared_examples/services/count_service_shared_examples.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+# The calling spec should use `:use_clean_rails_memory_store_caching`
+# when including this shared example. E.g.:
+#
+# describe MyCountService, :use_clean_rails_memory_store_caching do
+# it_behaves_like 'a counter caching service'
+# end
+shared_examples 'a counter caching service' do
+ describe '#count' do
+ it 'caches the count', :request_store do
+ subject.delete_cache
+ control_count = ActiveRecord::QueryRecorder.new { subject.count }.count
+ subject.delete_cache
+
+ expect { 2.times { subject.count } }.not_to exceed_query_limit(control_count)
+ end
+ end
+
+ describe '#refresh_cache' do
+ it 'refreshes the cache' do
+ original_count = subject.count
+ Rails.cache.write(subject.cache_key, original_count + 1, raw: subject.raw?)
+
+ subject.refresh_cache
+
+ expect(fetch_cache || 0).to eq(original_count)
+ end
+ end
+
+ describe '#delete_cache' do
+ it 'removes the cache' do
+ subject.count
+ subject.delete_cache
+
+ expect(fetch_cache).to be_nil
+ end
+ end
+
+ describe '#uncached_count' do
+ it 'does not cache the count' do
+ subject.delete_cache
+ subject.uncached_count
+
+ expect(fetch_cache).to be_nil
+ end
+ end
+
+ private
+
+ def fetch_cache
+ Rails.cache.read(subject.cache_key, raw: subject.raw?)
+ end
+end
diff --git a/vendor/licenses.csv b/vendor/licenses.csv
index 0c445aeac88..20aacff75fd 100644
--- a/vendor/licenses.csv
+++ b/vendor/licenses.csv
@@ -67,7 +67,6 @@
@babel/template,7.1.2,MIT
@babel/traverse,7.1.0,MIT
@babel/types,7.1.2,MIT
-@gitlab/csslab,1.8.0,MIT
@gitlab/svgs,1.41.0,MIT
@gitlab/ui,1.15.0,MIT
@sindresorhus/is,0.7.0,MIT
diff --git a/yarn.lock b/yarn.lock
index 712cdace0d7..c4fe112d833 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -964,13 +964,6 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
-"@gitlab/csslab@^1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@gitlab/csslab/-/csslab-1.9.0.tgz#22fca5b1a30cbd9ca46fc6f9485ecbaba4dc300c"
- integrity sha512-Zjayzokm7E2wgxUR/pxIMocdiBB5XHt2PEemdzD8qD+aQmMpMxSyIEMQk5Jq0Wgv+Rd5WXTolTw3kmb9l8ZeJg==
- dependencies:
- bootstrap "^4.1.3"
-
"@gitlab/eslint-config@^1.6.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@gitlab/eslint-config/-/eslint-config-1.6.0.tgz#1fd247d6ab477d53d4c330e05f007e3afa303689"
@@ -1637,7 +1630,7 @@ ansi-align@^2.0.0:
dependencies:
string-width "^2.0.0"
-ansi-colors@^3.0.0, ansi-colors@^3.2.4:
+ansi-colors@^3.0.0:
version "3.2.4"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
@@ -1647,13 +1640,6 @@ ansi-escapes@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
-ansi-gray@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251"
- integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE=
- dependencies:
- ansi-wrap "0.1.0"
-
ansi-html@0.0.7, ansi-html@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e"
@@ -1686,11 +1672,6 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
-ansi-wrap@0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
- integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768=
-
anymatch@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
@@ -2280,7 +2261,7 @@ bootstrap-vue@2.0.0-rc.27:
portal-vue "^2.1.5"
vue-functional-data-merge "^3.1.0"
-bootstrap@4.3.1, bootstrap@^4.1.3, bootstrap@^4.3.1:
+bootstrap@4.3.1, bootstrap@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"
integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==
@@ -2985,11 +2966,6 @@ color-name@1.1.3, color-name@^1.0.0:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
-color-support@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
- integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
-
colors@^1.1.0:
version "1.3.3"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d"
@@ -5027,16 +5003,6 @@ extsprintf@1.3.0, extsprintf@^1.2.0:
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
-fancy-log@^1.3.3:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7"
- integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==
- dependencies:
- ansi-gray "^0.1.1"
- color-support "^1.1.3"
- parse-node-version "^1.0.0"
- time-stamp "^1.0.0"
-
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
@@ -5782,16 +5748,6 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
-gulp-print@^5.0.2:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/gulp-print/-/gulp-print-5.0.2.tgz#8f379148218d2e168461baa74352e11d1bf7aa75"
- integrity sha512-iIpHMzC/b3gFvVXOfP9Jk94SWGIsDLVNUrxULRleQev+08ug07mh84b1AOlW6QDQdmInQiqDFqJN1UvhU2nXdg==
- dependencies:
- ansi-colors "^3.2.4"
- fancy-log "^1.3.3"
- map-stream "0.0.7"
- vinyl "^2.2.0"
-
gzip-size@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.0.0.tgz#a55ecd99222f4c48fd8c01c625ce3b349d0a0e80"
@@ -7965,11 +7921,6 @@ map-obj@^2.0.0:
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9"
integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk=
-map-stream@0.0.7:
- version "0.0.7"
- resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8"
- integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=
-
map-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
@@ -8165,10 +8116,10 @@ merge2@^1.2.3:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==
-mermaid@^8.2.3:
- version "8.2.3"
- resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-8.2.3.tgz#609bad45bedc3ee1a935161c11c3c22689cfecd9"
- integrity sha512-G2p9BAAEeTtogPs4YXM8KyX+TsZULlgk0tGvmBPfBZ5j3YCPxgAxG9ZzleiYNItF7M1hGkE485BDLN8DbfR+/Q==
+mermaid@^8.2.4:
+ version "8.2.4"
+ resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-8.2.4.tgz#52bcd45611fd8552ab9ac4e385d2766a0e38dcf7"
+ integrity sha512-2la1eJhu4n+Uug4zbxFnkETFDJ9U32OY/fRP8g8A1DrRdfT3Er+7CuUSvxfhIDxl+AxSEU4dXdqCiToZAVMCmQ==
dependencies:
"@braintree/sanitize-url" "^3.1.0"
d3 "^5.7.0"
@@ -8176,7 +8127,6 @@ mermaid@^8.2.3:
dagre-layout "^0.8.8"
documentation "^12.0.1"
graphlibrary "^2.2.0"
- gulp-print "^5.0.2"
he "^1.2.0"
lodash "^4.17.11"
minify "^4.1.1"
@@ -9145,11 +9095,6 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
-parse-node-version@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
- integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
-
parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
@@ -11783,11 +11728,6 @@ thunky@^0.1.0:
resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e"
integrity sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=
-time-stamp@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
- integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=
-
timeago.js@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/timeago.js/-/timeago.js-3.0.2.tgz#32a67e7c0d887ea42ca588d3aae26f77de5e76cc"
@@ -12618,7 +12558,7 @@ vinyl-sourcemap@^1.1.0:
remove-bom-buffer "^3.0.0"
vinyl "^2.0.0"
-vinyl@^2.0.0, vinyl@^2.1.0, vinyl@^2.2.0:
+vinyl@^2.0.0, vinyl@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86"
integrity sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==