summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md21
-rw-r--r--Gemfile.lock6
-rw-r--r--app/assets/javascripts/lib/utils/icons_path.js3
-rw-r--r--app/assets/javascripts/pdf/index.vue2
-rw-r--r--app/assets/javascripts/pdf/page/index.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/icon.vue4
-rw-r--r--app/models/application_setting.rb6
-rw-r--r--app/models/application_setting_implementation.rb4
-rw-r--r--app/models/clusters/cluster.rb16
-rw-r--r--app/models/concerns/token_authenticatable.rb4
-rw-r--r--app/models/project.rb6
-rw-r--r--app/services/metrics/dashboard/default_embed_service.rb2
-rw-r--r--app/validators/qualified_domain_array_validator.rb4
-rw-r--r--app/views/admin/application_settings/_help_page.html.haml2
-rw-r--r--app/views/admin/application_settings/_outbound.html.haml2
-rw-r--r--app/views/layouts/header/_help_dropdown.html.haml2
-rw-r--r--changelogs/unreleased/64091-fix-sprockets-paths.yml5
-rw-r--r--changelogs/unreleased/64731-fix-project-auto-devops-api.yml5
-rw-r--r--changelogs/unreleased/64870-can-t-save-pages-domain-form-with-let-s-encrypt-enabled-if-current-certificate-is-outdated.yml6
-rw-r--r--changelogs/unreleased/65019-auto-devops-dind-tls-fix.yml5
-rw-r--r--changelogs/unreleased/65019-job-templates-dind-tls-fix.yml5
-rw-r--r--changelogs/unreleased/dm-submodule-helper-routing.yml5
-rw-r--r--changelogs/unreleased/dm-submodule-links-nil.yml5
-rw-r--r--changelogs/unreleased/feat-add-support-page-link-in-help-menu.yml5
-rw-r--r--changelogs/unreleased/optimise-import-performance.yml5
-rw-r--r--changelogs/unreleased/sh-add-index-extern-uid.yml5
-rw-r--r--changelogs/unreleased/sh-fix-pdfjs-page-ordering.yml5
-rw-r--r--changelogs/unreleased/sh-remove-pdfjs-deprecations.yml5
-rw-r--r--changelogs/unreleased/sh-support-docker-oci-images.yml5
-rw-r--r--config/initializers/0_inject_enterprise_edition_module.rb17
-rw-r--r--config/webpack.config.js14
-rw-r--r--db/post_migrate/20190723105753_add_index_on_identities_lower_extern_uid_and_provider.rb19
-rw-r--r--db/schema.rb1
-rw-r--r--doc/administration/custom_hooks.md2
-rw-r--r--doc/administration/geo/replication/index.md10
-rw-r--r--doc/administration/raketasks/ldap.md25
-rw-r--r--doc/api/settings.md2
-rw-r--r--doc/ci/docker/using_docker_build.md2
-rw-r--r--doc/ci/docker/using_kaniko.md3
-rw-r--r--doc/ci/examples/browser_performance.md4
-rw-r--r--doc/ci/examples/code_quality.md2
-rw-r--r--doc/ci/multi_project_pipelines.md5
-rw-r--r--doc/ci/yaml/README.md35
-rw-r--r--doc/development/documentation/index.md54
-rw-r--r--doc/development/documentation/styleguide.md87
-rw-r--r--doc/development/ee_features.md46
-rw-r--r--doc/development/fe_guide/components.md45
-rw-r--r--doc/development/fe_guide/performance.md40
-rw-r--r--doc/development/fe_guide/style_guide_js.md859
-rw-r--r--doc/development/fe_guide/vuex.md44
-rw-r--r--doc/development/i18n/externalization.md221
-rw-r--r--doc/development/utilities.md128
-rw-r--r--doc/topics/git/numerous_undo_possibilities_in_git/index.md92
-rw-r--r--doc/topics/git/troubleshooting_git.md10
-rw-r--r--doc/university/training/end-user/README.md152
-rw-r--r--doc/university/training/topics/git_add.md30
-rw-r--r--doc/university/training/topics/git_log.md30
-rw-r--r--doc/university/training/topics/rollback_commits.md26
-rw-r--r--doc/university/training/topics/stash.md56
-rw-r--r--doc/university/training/topics/unstage.md28
-rw-r--r--doc/update/mysql_to_postgresql.md108
-rw-r--r--doc/user/group/saml_sso/scim_setup.md14
-rw-r--r--doc/user/profile/account/delete_account.md26
-rw-r--r--doc/user/profile/account/two_factor_authentication.md18
-rw-r--r--doc/user/profile/active_sessions.md23
-rw-r--r--doc/user/profile/index.md120
-rw-r--r--doc/user/profile/personal_access_tokens.md16
-rw-r--r--doc/user/profile/preferences.md30
-rw-r--r--doc/user/project/clusters/index.md12
-rw-r--r--doc/user/project/issues/csv_export.md2
-rw-r--r--doc/workflow/git_annex.md30
-rw-r--r--doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md145
-rw-r--r--doc/workflow/time_tracking.md13
-rw-r--r--doc/workflow/workflow.md38
-rw-r--r--lib/api/settings.rb2
-rw-r--r--lib/gitlab/gitaly_client.rb2
-rw-r--r--locale/gitlab.pot11
-rw-r--r--package.json2
-rw-r--r--qa/qa/runtime/env.rb4
-rw-r--r--qa/qa/service/kubernetes_cluster.rb2
-rw-r--r--rubocop/cop/inject_enterprise_edition_module.rb48
-rw-r--r--spec/fast_spec_helper.rb1
-rw-r--r--spec/features/admin/admin_settings_spec.rb34
-rw-r--r--spec/javascripts/boards/components/boards_selector_spec.js3
-rw-r--r--spec/javascripts/pdf/page_spec.js5
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb10
-rw-r--r--spec/models/application_setting_spec.rb2
-rw-r--r--spec/models/clusters/cluster_spec.rb45
-rw-r--r--spec/models/project_spec.rb18
-rw-r--r--spec/rubocop/cop/inject_enterprise_edition_module_spec.rb144
-rw-r--r--spec/services/metrics/dashboard/default_embed_service_spec.rb6
-rw-r--r--spec/support/helpers/features/notes_helpers.rb8
-rw-r--r--spec/support/helpers/graphql_helpers.rb8
-rw-r--r--spec/support/shared_examples/application_setting_examples.rb11
-rw-r--r--spec/validators/qualified_domain_array_validator_spec.rb30
-rw-r--r--yarn.lock32
96 files changed, 1815 insertions, 1451 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d93cc182c62..15b55f01c32 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,27 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 12.1.3
+
+### Fixed (11 changes)
+
+- Prevent multiple confirmation modals from opening when deleting a repository. !30532
+- Fix the project auto devops API. !30946
+- Fix "Certificate misses intermediates" UI error when enabling Let's Encrypt integration for pages domain. !30995
+- Fix xterm css not loading for environment terminal. !31023
+- Set DOCKER_TLS_CERTDIR in Auto Dev-Ops CI template to fix jobs using Docker-in-Docker. !31078
+- Set DOCKER_TLS_CERTDIR in CI job templates to fix Docker-in-Docker service. !31080
+- Support Docker OCI images. !31127
+- Fix error rendering submodules in MR diffs when there is no .gitmodules. !31162
+- Fix pdf.js rendering pages in the wrong order. !31222
+- Fix exception handling in Gitaly autodetection. !31285
+- Fix bug that caused diffs not to show on MRs with changes to submodules.
+
+### Performance (1 change)
+
+- Optimise import performance. !31045
+
+
## 12.1.2
### Security (1 change)
diff --git a/Gemfile.lock b/Gemfile.lock
index 45f1464a5b5..f89654c82fd 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -321,7 +321,7 @@ GEM
gitlab-markup (1.7.0)
gitlab-sidekiq-fetcher (0.4.0)
sidekiq (~> 5)
- gitlab-styles (2.7.0)
+ gitlab-styles (2.8.0)
rubocop (~> 0.69.0)
rubocop-gitlab-security (~> 0.1.0)
rubocop-performance (~> 1.1.0)
@@ -441,7 +441,7 @@ GEM
jaeger-client (0.10.0)
opentracing (~> 0.3)
thrift
- jaro_winkler (1.5.2)
+ jaro_winkler (1.5.3)
jira-ruby (1.4.1)
activesupport
multipart-post
@@ -837,7 +837,7 @@ GEM
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-prof (0.17.0)
- ruby-progressbar (1.10.0)
+ ruby-progressbar (1.10.1)
ruby-saml (1.7.2)
nokogiri (>= 1.5.10)
ruby_parser (3.13.1)
diff --git a/app/assets/javascripts/lib/utils/icons_path.js b/app/assets/javascripts/lib/utils/icons_path.js
new file mode 100644
index 00000000000..1a1c3c8e7b3
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/icons_path.js
@@ -0,0 +1,3 @@
+// any import of '@gitlab/svgs/dist/icons.svg' will be overridden with this
+// to avoid asset duplication between sprockets and webpack
+export default gon && gon.sprite_icons;
diff --git a/app/assets/javascripts/pdf/index.vue b/app/assets/javascripts/pdf/index.vue
index 14640c172cd..bbbd9789dc9 100644
--- a/app/assets/javascripts/pdf/index.vue
+++ b/app/assets/javascripts/pdf/index.vue
@@ -39,7 +39,7 @@ export default {
cMapUrl: '/assets/webpack/cmaps/',
cMapPacked: true,
})
- .then(this.renderPages)
+ .promise.then(this.renderPages)
.then(pages => {
this.pages = pages;
this.$emit('pdflabload');
diff --git a/app/assets/javascripts/pdf/page/index.vue b/app/assets/javascripts/pdf/page/index.vue
index d933fdf220a..65f84e75e86 100644
--- a/app/assets/javascripts/pdf/page/index.vue
+++ b/app/assets/javascripts/pdf/page/index.vue
@@ -18,7 +18,7 @@ export default {
},
computed: {
viewport() {
- return this.page.getViewport(this.scale);
+ return this.page.getViewport({ scale: this.scale });
},
context() {
return this.$refs.canvas.getContext('2d');
@@ -36,7 +36,7 @@ export default {
this.rendering = true;
this.page
.render(this.renderContext)
- .then(() => {
+ .promise.then(() => {
this.rendering = false;
})
.catch(error => {
diff --git a/app/assets/javascripts/vue_shared/components/icon.vue b/app/assets/javascripts/vue_shared/components/icon.vue
index 41c4c861566..fa89473da62 100644
--- a/app/assets/javascripts/vue_shared/components/icon.vue
+++ b/app/assets/javascripts/vue_shared/components/icon.vue
@@ -1,4 +1,6 @@
<script>
+import iconsPath from '@gitlab/svgs/dist/icons.svg';
+
// only allow classes in images.scss e.g. s12
const validSizes = [8, 10, 12, 14, 16, 18, 24, 32, 48, 72];
let iconValidator = () => true;
@@ -84,7 +86,7 @@ export default {
computed: {
spriteHref() {
- return `${gon.sprite_icons}#${this.name}`;
+ return `${iconsPath}#${this.name}`;
},
iconTestClass() {
return `ic-${this.name}`;
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index a769a8f07fd..9dbcef8abaa 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -42,9 +42,9 @@ class ApplicationSetting < ApplicationRecord
validates :uuid, presence: true
validates :outbound_local_requests_whitelist,
- length: { maximum: 1_000, message: N_('is too long (maximum is 1000 entries)') }
-
- validates :outbound_local_requests_whitelist, qualified_domain_array: true, allow_blank: true
+ length: { maximum: 1_000, message: N_('is too long (maximum is 1000 entries)') },
+ allow_nil: false,
+ qualified_domain_array: true
validates :session_expire_delay,
presence: true,
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 1e612bd0e78..6efd07a6008 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -163,6 +163,8 @@ module ApplicationSettingImplementation
def outbound_local_requests_whitelist_arrays
strong_memoize(:outbound_local_requests_whitelist_arrays) do
+ next [[], []] unless self.outbound_local_requests_whitelist
+
ip_whitelist = []
domain_whitelist = []
@@ -284,6 +286,8 @@ module ApplicationSettingImplementation
end
def domain_strings_to_array(values)
+ return [] unless values
+
values
.split(DOMAIN_LIST_SEPARATOR)
.reject(&:empty?)
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 8c044c86c47..8bb44b0ce40 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -100,12 +100,6 @@ module Clusters
scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) }
- scope :missing_kubernetes_namespace, -> (kubernetes_namespaces) do
- subquery = kubernetes_namespaces.select('1').where('clusters_kubernetes_namespaces.cluster_id = clusters.id')
-
- where('NOT EXISTS (?)', subquery)
- end
-
scope :with_knative_installed, -> { joins(:application_knative).merge(Clusters::Applications::Knative.available) }
scope :preload_knative, -> {
@@ -161,16 +155,6 @@ module Clusters
return platform_kubernetes if kubernetes?
end
- def all_projects
- if project_type?
- projects
- elsif group_type?
- first_group.all_projects
- else
- Project.none
- end
- end
-
def first_project
strong_memoize(:first_project) do
projects.first
diff --git a/app/models/concerns/token_authenticatable.rb b/app/models/concerns/token_authenticatable.rb
index 1293df571a3..4099039dd96 100644
--- a/app/models/concerns/token_authenticatable.rb
+++ b/app/models/concerns/token_authenticatable.rb
@@ -3,10 +3,8 @@
module TokenAuthenticatable
extend ActiveSupport::Concern
- private
-
class_methods do
- private # rubocop:disable Lint/UselessAccessModifier
+ private
def add_authentication_token_field(token_field, options = {})
if token_authenticatable_fields.include?(token_field)
diff --git a/app/models/project.rb b/app/models/project.rb
index cca7da8c49a..8f234fba04f 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -415,12 +415,6 @@ class Project < ApplicationRecord
.where(project_ci_cd_settings: { group_runners_enabled: true })
end
- scope :missing_kubernetes_namespace, -> (kubernetes_namespaces) do
- subquery = kubernetes_namespaces.select('1').where('clusters_kubernetes_namespaces.project_id = projects.id')
-
- where('NOT EXISTS (?)', subquery)
- end
-
enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 }
chronic_duration_attr :build_timeout_human_readable, :build_timeout,
diff --git a/app/services/metrics/dashboard/default_embed_service.rb b/app/services/metrics/dashboard/default_embed_service.rb
index 0967c5bcfeb..8b01b44fc98 100644
--- a/app/services/metrics/dashboard/default_embed_service.rb
+++ b/app/services/metrics/dashboard/default_embed_service.rb
@@ -23,7 +23,7 @@ module Metrics
# Returns a new dashboard with only the matching
# metrics from the system dashboard, stripped of groups.
# @return [Hash]
- def raw_dashboard
+ def get_raw_dashboard
panels = panel_groups.each_with_object([]) do |group, panels|
matched_panels = group['panels'].select { |panel| matching_panel?(panel) }
diff --git a/app/validators/qualified_domain_array_validator.rb b/app/validators/qualified_domain_array_validator.rb
index 986c146a9db..c3a79d21ac0 100644
--- a/app/validators/qualified_domain_array_validator.rb
+++ b/app/validators/qualified_domain_array_validator.rb
@@ -23,9 +23,9 @@ class QualifiedDomainArrayValidator < ActiveModel::EachValidator
private
def validate_value_present(record, attribute, value)
- return unless value.blank?
+ return unless value.nil?
- record.errors.add(attribute, _('entries cannot be blank'))
+ record.errors.add(attribute, _('entries cannot be nil'))
end
def validate_host_length(record, attribute, value)
diff --git a/app/views/admin/application_settings/_help_page.html.haml b/app/views/admin/application_settings/_help_page.html.haml
index a869f1bd4df..5e5ab1e4269 100644
--- a/app/views/admin/application_settings/_help_page.html.haml
+++ b/app/views/admin/application_settings/_help_page.html.haml
@@ -16,6 +16,6 @@
.form-group
= f.label :help_page_support_url, _('Support page URL'), class: 'label-bold'
= f.text_field :help_page_support_url, class: 'form-control', placeholder: 'http://company.example.com/getting-help', :'aria-describedby' => 'support_help_block'
- %span.form-text.text-muted#support_help_block= _('Alternate support URL for help page')
+ %span.form-text.text-muted#support_help_block= _('Alternate support URL for help page and help dropdown')
= f.submit _('Save changes'), class: "btn btn-success"
diff --git a/app/views/admin/application_settings/_outbound.html.haml b/app/views/admin/application_settings/_outbound.html.haml
index e58bb526c11..4fecdb59e1d 100644
--- a/app/views/admin/application_settings/_outbound.html.haml
+++ b/app/views/admin/application_settings/_outbound.html.haml
@@ -13,7 +13,7 @@
= _('Whitelist to allow requests to the local network from hooks and services')
= f.text_area :outbound_local_requests_whitelist_raw, placeholder: "example.com, 192.168.1.1", class: 'form-control', rows: 8
%span.form-text.text-muted
- = _('Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are disabled. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The whitelist can hold a maximum of 4000 entries. Domains should use IDNA encoding. Ex: domain.com, 192.168.1.1, 127.0.0.0/28.')
+ = _('Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The whitelist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com.')
.form-group
.form-check
diff --git a/app/views/layouts/header/_help_dropdown.html.haml b/app/views/layouts/header/_help_dropdown.html.haml
index 5643a508ddc..41d7aa3741a 100644
--- a/app/views/layouts/header/_help_dropdown.html.haml
+++ b/app/views/layouts/header/_help_dropdown.html.haml
@@ -2,6 +2,8 @@
- if current_user_menu?(:help)
%li
= link_to _("Help"), help_path
+ %li
+ = link_to _("Support"), support_url
= render_if_exists "shared/learn_gitlab_menu_item"
%li.divider
%li
diff --git a/changelogs/unreleased/64091-fix-sprockets-paths.yml b/changelogs/unreleased/64091-fix-sprockets-paths.yml
deleted file mode 100644
index fcd8b2faa49..00000000000
--- a/changelogs/unreleased/64091-fix-sprockets-paths.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix xterm css not loading for environment terminal
-merge_request: 31023
-author:
-type: fixed
diff --git a/changelogs/unreleased/64731-fix-project-auto-devops-api.yml b/changelogs/unreleased/64731-fix-project-auto-devops-api.yml
deleted file mode 100644
index 7fe2c036773..00000000000
--- a/changelogs/unreleased/64731-fix-project-auto-devops-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix the project auto devops API
-merge_request: 30946
-author:
-type: fixed
diff --git a/changelogs/unreleased/64870-can-t-save-pages-domain-form-with-let-s-encrypt-enabled-if-current-certificate-is-outdated.yml b/changelogs/unreleased/64870-can-t-save-pages-domain-form-with-let-s-encrypt-enabled-if-current-certificate-is-outdated.yml
deleted file mode 100644
index 291901d64ed..00000000000
--- a/changelogs/unreleased/64870-can-t-save-pages-domain-form-with-let-s-encrypt-enabled-if-current-certificate-is-outdated.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Fix "Certificate misses intermediates" UI error when enabling Let's Encrypt
- integration for pages domain
-merge_request: 30995
-author:
-type: fixed
diff --git a/changelogs/unreleased/65019-auto-devops-dind-tls-fix.yml b/changelogs/unreleased/65019-auto-devops-dind-tls-fix.yml
deleted file mode 100644
index 3eea3e551ce..00000000000
--- a/changelogs/unreleased/65019-auto-devops-dind-tls-fix.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Set DOCKER_TLS_CERTDIR in Auto Dev-Ops CI template to fix jobs using Docker-in-Docker
-merge_request: 31078
-author:
-type: fixed
diff --git a/changelogs/unreleased/65019-job-templates-dind-tls-fix.yml b/changelogs/unreleased/65019-job-templates-dind-tls-fix.yml
deleted file mode 100644
index c7c02486d61..00000000000
--- a/changelogs/unreleased/65019-job-templates-dind-tls-fix.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Set DOCKER_TLS_CERTDIR in CI job templates to fix Docker-in-Docker service
-merge_request: 31080
-author:
-type: fixed
diff --git a/changelogs/unreleased/dm-submodule-helper-routing.yml b/changelogs/unreleased/dm-submodule-helper-routing.yml
deleted file mode 100644
index 779d4d167df..00000000000
--- a/changelogs/unreleased/dm-submodule-helper-routing.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix bug that caused diffs not to show on MRs with changes to submodules
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/dm-submodule-links-nil.yml b/changelogs/unreleased/dm-submodule-links-nil.yml
deleted file mode 100644
index c09ca41d01d..00000000000
--- a/changelogs/unreleased/dm-submodule-links-nil.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix error rendering submodules in MR diffs when there is no .gitmodules
-merge_request: 31162
-author:
-type: fixed
diff --git a/changelogs/unreleased/feat-add-support-page-link-in-help-menu.yml b/changelogs/unreleased/feat-add-support-page-link-in-help-menu.yml
new file mode 100644
index 00000000000..2cddd52212e
--- /dev/null
+++ b/changelogs/unreleased/feat-add-support-page-link-in-help-menu.yml
@@ -0,0 +1,5 @@
+---
+title: Add admin-configurable "Support page URL" link to top Help dropdown menu
+merge_request: 30459
+author: Diego Louzán
+type: added
diff --git a/changelogs/unreleased/optimise-import-performance.yml b/changelogs/unreleased/optimise-import-performance.yml
deleted file mode 100644
index c63f44d5109..00000000000
--- a/changelogs/unreleased/optimise-import-performance.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Optimise import performance
-merge_request: 31045
-author:
-type: performance
diff --git a/changelogs/unreleased/sh-add-index-extern-uid.yml b/changelogs/unreleased/sh-add-index-extern-uid.yml
new file mode 100644
index 00000000000..531770237a8
--- /dev/null
+++ b/changelogs/unreleased/sh-add-index-extern-uid.yml
@@ -0,0 +1,5 @@
+---
+title: Add partial index on identities table to speed up LDAP lookups
+merge_request: 26710
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-fix-pdfjs-page-ordering.yml b/changelogs/unreleased/sh-fix-pdfjs-page-ordering.yml
deleted file mode 100644
index 84161c51905..00000000000
--- a/changelogs/unreleased/sh-fix-pdfjs-page-ordering.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix pdf.js rendering pages in the wrong order
-merge_request: 31222
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-remove-pdfjs-deprecations.yml b/changelogs/unreleased/sh-remove-pdfjs-deprecations.yml
new file mode 100644
index 00000000000..a00ceedf3f4
--- /dev/null
+++ b/changelogs/unreleased/sh-remove-pdfjs-deprecations.yml
@@ -0,0 +1,5 @@
+---
+title: Remove pdf.js deprecation warnings
+merge_request: 31253
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-support-docker-oci-images.yml b/changelogs/unreleased/sh-support-docker-oci-images.yml
deleted file mode 100644
index 2dcf980fa50..00000000000
--- a/changelogs/unreleased/sh-support-docker-oci-images.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Support Docker OCI images
-merge_request: 31127
-author:
-type: fixed
diff --git a/config/initializers/0_inject_enterprise_edition_module.rb b/config/initializers/0_inject_enterprise_edition_module.rb
new file mode 100644
index 00000000000..4b21732e179
--- /dev/null
+++ b/config/initializers/0_inject_enterprise_edition_module.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module InjectEnterpriseEditionModule
+ def prepend_if_ee(constant)
+ prepend(constant.constantize) if Gitlab.ee?
+ end
+
+ def extend_if_ee(constant)
+ extend(constant.constantize) if Gitlab.ee?
+ end
+
+ def include_if_ee(constant)
+ include(constant.constantize) if Gitlab.ee?
+ end
+end
+
+Module.prepend(InjectEnterpriseEditionModule)
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 4b6a9e4b99e..442b4b4c21e 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -90,6 +90,12 @@ const alias = {
// the following resolves files which are different between CE and EE
ee_else_ce: path.join(ROOT_PATH, 'app/assets/javascripts'),
+
+ // override loader path for icons.svg so we do not duplicate this asset
+ '@gitlab/svgs/dist/icons.svg': path.join(
+ ROOT_PATH,
+ 'app/assets/javascripts/lib/utils/icons_path.js',
+ ),
};
if (IS_EE) {
@@ -158,7 +164,15 @@ module.exports = {
loader: 'graphql-tag/loader',
},
{
+ test: /icons\.svg$/,
+ loader: 'file-loader',
+ options: {
+ name: '[name].[hash:8].[ext]',
+ },
+ },
+ {
test: /\.svg$/,
+ exclude: /icons\.svg$/,
loader: 'raw-loader',
},
{
diff --git a/db/post_migrate/20190723105753_add_index_on_identities_lower_extern_uid_and_provider.rb b/db/post_migrate/20190723105753_add_index_on_identities_lower_extern_uid_and_provider.rb
new file mode 100644
index 00000000000..36ecca4821f
--- /dev/null
+++ b/db/post_migrate/20190723105753_add_index_on_identities_lower_extern_uid_and_provider.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddIndexOnIdentitiesLowerExternUidAndProvider < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ INDEX_NAME = "index_on_identities_lower_extern_uid_and_provider"
+
+ def up
+ add_concurrent_index(:identities, 'lower(extern_uid), provider', name: INDEX_NAME)
+ end
+
+ def down
+ remove_concurrent_index_by_name(:identities, INDEX_NAME)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f6b7e22fe09..6f5fc6c65eb 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1580,6 +1580,7 @@ ActiveRecord::Schema.define(version: 2019_07_29_090456) do
t.datetime "updated_at"
t.integer "saml_provider_id"
t.string "secondary_extern_uid"
+ t.index "lower((extern_uid)::text), provider", name: "index_on_identities_lower_extern_uid_and_provider"
t.index ["saml_provider_id"], name: "index_identities_on_saml_provider_id", where: "(saml_provider_id IS NOT NULL)"
t.index ["user_id"], name: "index_identities_on_user_id"
end
diff --git a/doc/administration/custom_hooks.md b/doc/administration/custom_hooks.md
index 113514e1ee8..32462a95a1a 100644
--- a/doc/administration/custom_hooks.md
+++ b/doc/administration/custom_hooks.md
@@ -21,7 +21,7 @@ administrators can add custom git hooks to any GitLab project.
## Create a custom Git hook for a repository
Server-side Git hooks are typically placed in the repository's `hooks`
-subdirectory. In GitLab, hook directories are are symlinked to the gitlab-shell
+subdirectory. In GitLab, hook directories are symlinked to the gitlab-shell
`hooks` directory for ease of maintenance between gitlab-shell upgrades.
Custom hooks are implemented differently, but the behavior is exactly the same
once the hook is created. Follow the steps below to set up a custom hook for a
diff --git a/doc/administration/geo/replication/index.md b/doc/administration/geo/replication/index.md
index f0d329d5296..b5789c87e47 100644
--- a/doc/administration/geo/replication/index.md
+++ b/doc/administration/geo/replication/index.md
@@ -1,5 +1,11 @@
# Geo Replication **(PREMIUM ONLY)**
+> - Introduced in GitLab Enterprise Edition 8.9.
+> - Using Geo in combination with
+> [High Availability](../../high_availability/README.md)
+> is considered **Generally Available** (GA) in
+> [GitLab Premium](https://about.gitlab.com/pricing/) 10.4.
+
Geo is the solution for widely distributed development teams.
## Overview
@@ -8,14 +14,14 @@ Fetching large repositories can take a long time for teams located far from a si
Geo provides local, read-only instances of your GitLab instances, reducing the time it takes to clone and fetch large repositories and speeding up development.
+> **Notes:**
+>
> - Geo is part of [GitLab Premium](https://about.gitlab.com/pricing/#self-managed).
-> - Introduced in GitLab Enterprise Edition 8.9.
> - We recommend you use:
> - At least GitLab Enterprise Edition 10.0 for basic Geo features.
> - The latest version for a better experience.
> - Make sure that all nodes run the same GitLab version.
> - Geo requires PostgreSQL 9.6 and Git 2.9, in addition to GitLab's usual [minimum requirements](../../../install/requirements.md).
-> - Using Geo in combination with [High Availability](../../high_availability/README.md) is considered **Generally Available** (GA) in GitLab [GitLab Premium](https://about.gitlab.com/pricing/) 10.4.
For a video introduction to Geo, see [Introduction to GitLab Geo - GitLab Features](https://www.youtube.com/watch?v=-HDLxSjEh6w).
diff --git a/doc/administration/raketasks/ldap.md b/doc/administration/raketasks/ldap.md
index 91fc0133d56..e880d76e756 100644
--- a/doc/administration/raketasks/ldap.md
+++ b/doc/administration/raketasks/ldap.md
@@ -28,6 +28,31 @@ limit by passing a number to the check task:
rake gitlab:ldap:check[50]
```
+## Run a Group Sync
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/14735) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.3.
+
+The following task will run a [group sync](../auth/ldap-ee.md#group-sync) immediately. This is valuable
+when you'd like to update all configured group memberships against LDAP without
+waiting for the next scheduled group sync to be run.
+
+NOTE: **NOTE:**
+If you'd like to change the frequency at which a group sync is performed,
+[adjust the cron schedule](../auth/ldap-ee.md#adjusting-ldap-group-sync-schedule)
+instead.
+
+**Omnibus Installation**
+
+```
+sudo gitlab-rake gitlab:ldap:group_sync
+```
+
+**Source Installation**
+
+```bash
+bundle exec rake gitlab:ldap:group_sync
+```
+
## Rename a provider
If you change the LDAP server ID in `gitlab.yml` or `gitlab.rb` you will need
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 68da88af698..c3ac70f0579 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -230,7 +230,7 @@ are listed in the descriptions of the relevant settings.
| `gravatar_enabled` | boolean | no | Enable Gravatar. |
| `hashed_storage_enabled` | boolean | no | Create new projects using hashed storage paths: Enable immutable, hash-based paths and repository names to store repositories on disk. This prevents repositories from having to be moved or renamed when the Project URL changes and may improve disk I/O performance. (EXPERIMENTAL) |
| `help_page_hide_commercial_content` | boolean | no | Hide marketing-related entries from help. |
-| `help_page_support_url` | string | no | Alternate support URL for help page. |
+| `help_page_support_url` | string | no | Alternate support URL for help page and help dropdown. |
| `help_page_text` | string | no | Custom text displayed on the help page. |
| `help_text` | string | no | **(PREMIUM)** GitLab server administrator information |
| `hide_third_party_offers` | boolean | no | Do not display offers from third parties within GitLab. |
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index 9f1ce1fc230..10a21edbd34 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -91,7 +91,7 @@ NOTE: **Note:**
By adding `gitlab-runner` to the `docker` group you are effectively granting `gitlab-runner` full root permissions.
For more information please read [On Docker security: `docker` group considered harmful](https://www.andreas-jung.com/contents/on-docker-security-docker-group-considered-harmful).
-### Use docker-in-docker executor
+### Use docker-in-docker workflow with Docker executor
The second approach is to use the special docker-in-docker (dind)
[Docker image](https://hub.docker.com/_/docker/) with all tools installed
diff --git a/doc/ci/docker/using_kaniko.md b/doc/ci/docker/using_kaniko.md
index 50f1ac3d54a..925653f9fdf 100644
--- a/doc/ci/docker/using_kaniko.md
+++ b/doc/ci/docker/using_kaniko.md
@@ -11,7 +11,8 @@ Requires GitLab Runner 11.2 and above.
container images from a Dockerfile, inside a container or Kubernetes cluster.
kaniko solves two problems with using the
-[docker-in-docker build](using_docker_build.md#use-docker-in-docker-executor) method:
+[docker-in-docker
+build](using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor) method:
- Docker-in-docker requires [privileged mode](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities)
in order to function, which is a significant security concern.
diff --git a/doc/ci/examples/browser_performance.md b/doc/ci/examples/browser_performance.md
index 8ecac4a5a4f..3266e5dc62e 100644
--- a/doc/ci/examples/browser_performance.md
+++ b/doc/ci/examples/browser_performance.md
@@ -15,7 +15,7 @@ your code by using GitLab CI/CD and [sitespeed.io](https://www.sitespeed.io)
using Docker-in-Docker.
First, you need GitLab Runner with
-[docker-in-docker executor](../docker/using_docker_build.md#use-docker-in-docker-executor).
+[docker-in-docker build](../docker/using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor).
Once you set up the Runner, add a new job to `.gitlab-ci.yml` that
generates the expected report:
@@ -155,4 +155,4 @@ performance:
paths:
- performance.json
- sitespeed-results/
-``` \ No newline at end of file
+```
diff --git a/doc/ci/examples/code_quality.md b/doc/ci/examples/code_quality.md
index e63470ec9d9..69bad6b4c25 100644
--- a/doc/ci/examples/code_quality.md
+++ b/doc/ci/examples/code_quality.md
@@ -14,7 +14,7 @@ This example shows how to run Code Quality on your code by using GitLab CI/CD
and Docker.
First, you need GitLab Runner with
-[docker-in-docker executor](../docker/using_docker_build.md#use-docker-in-docker-executor).
+[docker-in-docker executor](../docker/using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor).
Once you set up the Runner, include the CodeQuality template in your CI config:
diff --git a/doc/ci/multi_project_pipelines.md b/doc/ci/multi_project_pipelines.md
index 463b9194c58..ced4344a0b0 100644
--- a/doc/ci/multi_project_pipelines.md
+++ b/doc/ci/multi_project_pipelines.md
@@ -171,6 +171,11 @@ In this scenario, the `UPSTREAM_BRANCH` variable with a value related to the
upstream pipeline will be passed to the `downstream-job` job, and will be available
within the context of all downstream builds.
+NOTE: **Tip:**
+Upstream pipelines take precedence over downstream ones. If there are two
+variables with the same name defined in both upstream and downstream projects,
+the ones defined in the upstream project will take precedence.
+
### Limitations
Because bridge jobs are a little different to regular jobs, it is not
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 09b9fc87986..201047b70b9 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -1771,18 +1771,41 @@ sequentially from `job_name 1/N` to `job_name N/N`.
For every job, `CI_NODE_INDEX` and `CI_NODE_TOTAL` [environment variables](../variables/README.md#predefined-environment-variables) are set.
-A simple example:
+Marking a job to be run in parallel requires only a simple addition to your configuration file:
-```yaml
-test:
- script: rspec
- parallel: 5
+```diff
+ test:
+ script: rspec
++ parallel: 5
```
-
TIP: **Tip:**
Parallelize tests suites across parallel jobs.
Different languages have different tools to facilitate this.
+A simple example using [Sempahore Test Boosters](https://github.com/renderedtext/test-boosters) and RSpec to run some Ruby tests:
+
+```ruby
+# Gemfile
+source 'https://rubygems.org'
+
+gem 'rspec'
+gem 'semaphore_test_boosters'
+```
+
+```yaml
+test:
+ parallel: 3
+ script:
+ - bundle
+ - bundle exec rspec_booster --job $CI_NODE_INDEX/$CI_NODE_TOTAL
+```
+
+CAUTION: **Caution:**
+Please be aware that semaphore_test_boosters reports usages statistics to the author.
+
+You can then navigate to the **Jobs** tab of a new pipeline build and see your RSpec
+job split into three separate jobs.
+
### `trigger` **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/8997) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.8.
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index d717b17136e..19b26618882 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -111,18 +111,18 @@ For example, if you were to move `doc/workflow/lfs/lfs_administration.md` to
1. Copy `doc/workflow/lfs/lfs_administration.md` to `doc/administration/lfs.md`
1. Replace the contents of `doc/workflow/lfs/lfs_administration.md` with:
- ```md
- This document was moved to [another location](../../administration/lfs.md).
- ```
+ ```md
+ This document was moved to [another location](../../administration/lfs.md).
+ ```
1. Find and replace any occurrences of the old location with the new one.
A quick way to find them is to use `git grep`. First go to the root directory
where you cloned the `gitlab-ce` repository and then do:
- ```sh
- git grep -n "workflow/lfs/lfs_administration"
- git grep -n "lfs/lfs_administration"
- ```
+ ```sh
+ git grep -n "workflow/lfs/lfs_administration"
+ git grep -n "lfs/lfs_administration"
+ ```
NOTE: **Note:**
If the document being moved has any Disqus comments on it, there are extra steps
@@ -296,45 +296,45 @@ You can combine one or more of the following:
1. **Linking to an anchor link.** Use `anchor` as part of the `help_page_path`
method:
- ```haml
- = link_to 'Help page', help_page_path('user/permissions', anchor: 'anchor-link')
- ```
+ ```haml
+ = link_to 'Help page', help_page_path('user/permissions', anchor: 'anchor-link')
+ ```
1. **Opening links in a new tab.** This should be the default behavior:
- ```haml
- = link_to 'Help page', help_page_path('user/permissions'), target: '_blank'
- ```
+ ```haml
+ = link_to 'Help page', help_page_path('user/permissions'), target: '_blank'
+ ```
1. **Linking to a circle icon.** Usually used in settings where a long
description cannot be used, like near checkboxes. You can basically use
any font awesome icon, but prefer the `question-circle`:
- ```haml
- = link_to icon('question-circle'), help_page_path('user/permissions')
- ```
+ ```haml
+ = link_to icon('question-circle'), help_page_path('user/permissions')
+ ```
1. **Using a button link.** Useful in places where text would be out of context
with the rest of the page layout:
- ```haml
- = link_to 'Help page', help_page_path('user/permissions'), class: 'btn btn-info'
- ```
+ ```haml
+ = link_to 'Help page', help_page_path('user/permissions'), class: 'btn btn-info'
+ ```
1. **Using links inline of some text.**
- ```haml
- Description to #{link_to 'Help page', help_page_path('user/permissions')}.
- ```
+ ```haml
+ Description to #{link_to 'Help page', help_page_path('user/permissions')}.
+ ```
1. **Adding a period at the end of the sentence.** Useful when you don't want
the period to be part of the link:
- ```haml
- = succeed '.' do
- Learn more in the
- = link_to 'Help page', help_page_path('user/permissions')
- ```
+ ```haml
+ = succeed '.' do
+ Learn more in the
+ = link_to 'Help page', help_page_path('user/permissions')
+ ```
### GitLab `/help` tests
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index dd798777c12..e84d65f424e 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -36,8 +36,8 @@ For the Troubleshooting sections, people in GitLab Support can merge additions t
Include any media types/sources if the content is relevant to readers. You can freely include or link presentations, diagrams, videos, etc.; no matter who it was originally composed for, if it is helpful to any of our audiences, we can include it.
- - If you use an image that has a separate source file (for example, a vector or diagram format), link the image to the source file so that it may be reused or updated by anyone.
- - Do not copy and paste content from other sources unless it is a limited quotation with the source cited. Typically it is better to either rephrase relevant information in your own words or link out to the other source.
+- If you use an image that has a separate source file (for example, a vector or diagram format), link the image to the source file so that it may be reused or updated by anyone.
+- Do not copy and paste content from other sources unless it is a limited quotation with the source cited. Typically it is better to either rephrase relevant information in your own words or link out to the other source.
### No special types
@@ -237,14 +237,14 @@ Do not include the same information in multiple places. [Link to a SSOT instead.
- Use sentence case for titles, headings, labels, menu items, and buttons.
- Insert an empty line between different markups (e.g., after every paragraph, header, list, etc). Example:
- ```md
- ## Header
+ ```md
+ ## Header
- Paragraph.
+ Paragraph.
- - List item 1
- - List item 2
- ```
+ - List item 1
+ - List item 2
+ ```
### Tables overlapping the TOC
@@ -303,12 +303,12 @@ Check specific punctuation rules for [list items](#list-items) below.
- Be consistent throughout the list: if the majority of the items do not end in a period, do not end any of the items in a period, even if they consist of a complete sentence. The opposite is also valid: if the majority of the items end with a period, end all with a period.
- Separate list items from explanatory text with a colon (`:`). For example:
- ```md
- The list is as follows:
+ ```md
+ The list is as follows:
- - First item: this explains the first item.
- - Second item: this explains the second item.
- ```
+ - First item: this explains the first item.
+ - Second item: this explains the second item.
+ ```
**Examples:**
@@ -520,16 +520,16 @@ To embed a video, follow the instructions below and make sure
you have your MR reviewed and approved by a technical writer.
1. Copy the code below and paste it into your markdown file.
- Leave a blank line above and below it. Do NOT edit the code
- (don't remove or add any spaces, etc).
+ Leave a blank line above and below it. Do NOT edit the code
+ (don't remove or add any spaces, etc).
1. On YouTube, visit the video URL you want to display. Copy
- the regular URL from your browser (`https://www.youtube.com/watch?v=VIDEO-ID`)
- and replace the video title and link in the line under `<div class="video-fallback">`.
+ the regular URL from your browser (`https://www.youtube.com/watch?v=VIDEO-ID`)
+ and replace the video title and link in the line under `<div class="video-fallback">`.
1. On YouTube, click **Share**, then **Embed**.
1. Copy the `<iframe>` source (`src`) **URL only**
- (`https://www.youtube.com/embed/VIDEO-ID`),
- and paste it, replacing the content of the `src` field in the
- `iframe` tag.
+ (`https://www.youtube.com/embed/VIDEO-ID`),
+ and paste it, replacing the content of the `src` field in the
+ `iframe` tag.
```html
leave a blank line here
@@ -611,7 +611,7 @@ In most cases, content considered for a note should be included:
#### When to use
Use a note when there is a reason that most or all readers who browse the
-section should see the content. That is, if missed, it’s likely to cause
+section should see the content. That is, if missed, it’s likely to cause
major trouble for a minority of users or significant trouble for a majority
of users.
@@ -747,24 +747,24 @@ a helpful link back to how the feature was developed.
- For features that need to declare the GitLab version that the feature was introduced. Text similar
to the following should be added immediately below the heading as a blockquote:
- ```md
- > Introduced in GitLab 11.3.
- ```
+ ```md
+ > Introduced in GitLab 11.3.
+ ```
- Whenever possible, version text should have a link to the issue, merge request, or epic that introduced the feature.
An issue is preferred over a merge request, and a merge request is preferred over an epic. For example:
- ```md
- > [Introduced](<link-to-issue>) in GitLab 11.3.
- ```
+ ```md
+ > [Introduced](<link-to-issue>) in GitLab 11.3.
+ ```
- If the feature is only available in GitLab Enterprise Edition, mention
the [paid tier](https://about.gitlab.com/handbook/marketing/product-marketing/#tiers)
the feature is available in:
- ```md
- > [Introduced](<link-to-issue>) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.3.
- ```
+ ```md
+ > [Introduced](<link-to-issue>) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.3.
+ ```
### Removing version text
@@ -871,14 +871,14 @@ When there is a list of steps to perform, usually that entails editing the
configuration file and reconfiguring/restarting GitLab. In such case, follow
the style below as a guide:
-```md
+````md
**For Omnibus installations**
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- external_url "https://gitlab.example.com"
- ```
+ ```ruby
+ external_url "https://gitlab.example.com"
+ ```
1. Save the file and [reconfigure] GitLab for the changes to take effect.
@@ -888,17 +888,16 @@ the style below as a guide:
1. Edit `config/gitlab.yml`:
- ```yaml
- gitlab:
- host: "gitlab.example.com"
- ```
+ ```yaml
+ gitlab:
+ host: "gitlab.example.com"
+ ```
1. Save the file and [restart] GitLab for the changes to take effect.
-
[reconfigure]: path/to/administration/restart_gitlab.md#omnibus-gitlab-reconfigure
[restart]: path/to/administration/restart_gitlab.md#installations-from-source
-```
+````
In this case:
@@ -917,9 +916,9 @@ on this document. Further explanation is given below.
- Every method must have the REST API request. For example:
- ```
- GET /projects/:id/repository/branches
- ```
+ ```
+ GET /projects/:id/repository/branches
+ ```
- Every method must have a detailed
[description of the parameters](#method-description).
@@ -971,7 +970,7 @@ You can use the following fake tokens as examples.
| Token type | Token value |
|:----------------------|:-------------------------------------------------------------------|
-| Private user token | `<your_access_token>` |
+| Private user token | `<your_access_token>` |
| Personal access token | `n671WNGecHugsdEDPsyo` |
| Application ID | `2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6` |
| Application secret | `04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df` |
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 7131b717353..2217dedccd3 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -125,20 +125,24 @@ This also applies to views.
### EE features based on CE features
For features that build on existing CE features, write a module in the `EE`
-namespace and `prepend` it in the CE class, on the last line of the file that
-the class resides in. This makes conflicts less likely to happen during CE to EE
-merges because only one line is added to the CE class - the `prepend` line. For
-example, to prepend a module into the `User` class you would use the following
-approach:
+namespace and inject it in the CE class, on the last line of the file that the
+class resides in. This makes conflicts less likely to happen during CE to EE
+merges because only one line is added to the CE class - the line that injects
+the module. For example, to prepend a module into the `User` class you would use
+the following approach:
```ruby
class User < ActiveRecord::Base
# ... lots of code here ...
end
-User.prepend(EE::User)
+User.prepend_if_ee('EE::User')
```
+Do not use methods such as `prepend`, `extend`, and `include`. Instead, use
+`prepend_if_ee`, `extend_if_ee`, or `include_if_ee`. These methods take a
+_String_ containing the full module name as the argument, not the module itself.
+
Since the module would require an `EE` namespace, the file should also be
put in an `ee/` sub-directory. For example, we want to extend the user model
in EE, so we have a module called `::EE::User` put inside
@@ -255,7 +259,7 @@ class ApplicationController < ActionController::Base
# ...
end
-ApplicationController.prepend(EE::ApplicationController)
+ApplicationController.prepend_if_ee('EE::ApplicationController')
```
And create a new file in the `ee/` sub-directory with the altered
@@ -504,9 +508,9 @@ EE-specific LDAP classes in `ee/lib/ee/gitlab/ldap`.
### Code in `lib/api/`
-It can be very tricky to extend EE features by a single line of `prepend`,
-and for each different [Grape](https://github.com/ruby-grape/grape) feature,
-we might need different strategies to extend it. To apply different strategies
+It can be very tricky to extend EE features by a single line of `prepend_if_ee`,
+and for each different [Grape](https://github.com/ruby-grape/grape) feature, we
+might need different strategies to extend it. To apply different strategies
easily, we would use `extend ActiveSupport::Concern` in the EE module.
Put the EE module files following
@@ -543,12 +547,12 @@ constants.
We can define `params` and utilize `use` in another `params` definition to
include params defined in EE. However, we need to define the "interface" first
in CE in order for EE to override it. We don't have to do this in other places
-due to `prepend`, but Grape is complex internally and we couldn't easily do
-that, so we'll follow regular object-oriented practices that we define the
+due to `prepend_if_ee`, but Grape is complex internally and we couldn't easily
+do that, so we'll follow regular object-oriented practices that we define the
interface first here.
For example, suppose we have a few more optional params for EE. We can move the
-params out of the `Grape::API` class to a helper module, so we can `prepend` it
+params out of the `Grape::API` class to a helper module, so we can inject it
before it would be used in the class.
```ruby
@@ -583,7 +587,7 @@ module API
end
end
-API::Helpers::ProjectsHelpers.prepend(EE::API::Helpers::ProjectsHelpers)
+API::Helpers::ProjectsHelpers.prepend_if_ee('EE::API::Helpers::ProjectsHelpers')
```
We could override it in EE module:
@@ -624,7 +628,7 @@ module API
end
end
-API::JobArtifacts.prepend(EE::API::JobArtifacts)
+API::JobArtifacts.prepend_if_ee('EE::API::JobArtifacts')
```
And then we can follow regular object-oriented practices to override it:
@@ -677,7 +681,7 @@ module API
end
end
-API::MergeRequests.prepend(EE::API::MergeRequests)
+API::MergeRequests.prepend_if_ee('EE::API::MergeRequests')
```
Note that `update_merge_request_ee` doesn't do anything in CE, but
@@ -717,8 +721,8 @@ Sometimes we need to use different arguments for a particular API route, and we
can't easily extend it with an EE module because Grape has different context in
different blocks. In order to overcome this, we need to move the data to a class
method that resides in a separate module or class. This allows us to extend that
-module or class before its data is used, without having to place a `prepend` in
-the middle of CE code.
+module or class before its data is used, without having to place a
+`prepend_if_ee` in the middle of CE code.
For example, in one place we need to pass an extra argument to
`at_least_one_of` so that the API could consider an EE-only argument as the
@@ -739,7 +743,7 @@ module API
end
end
-API::MergeRequests::Parameters.prepend(EE::API::MergeRequests::Parameters)
+API::MergeRequests::Parameters.prepend_if_ee('EE::API::MergeRequests::Parameters')
# api/merge_requests.rb
module API
@@ -789,7 +793,7 @@ class Identity < ActiveRecord::Base
[:provider]
end
- prepend EE::Identity
+ prepend_if_ee('EE::Identity')
validates :extern_uid,
allow_blank: true,
@@ -841,7 +845,7 @@ class Identity < ActiveRecord::Base
end
end
-Identity::UniquenessScopes.prepend(EE::Identity::UniquenessScopes)
+Identity::UniquenessScopes.prepend_if_ee('EE::Identity::UniquenessScopes')
# app/models/identity.rb
class Identity < ActiveRecord::Base
diff --git a/doc/development/fe_guide/components.md b/doc/development/fe_guide/components.md
index 52462a4bec9..096ce8ca25a 100644
--- a/doc/development/fe_guide/components.md
+++ b/doc/development/fe_guide/components.md
@@ -14,28 +14,29 @@ See also the [corresponding UX guide](https://design.gitlab.com/#/components/dro
1. Use the HTML structure provided by the [docs][bootstrap-dropdowns]
1. Add a specific class to the top level `.dropdown` element
- ```Haml
- .dropdown.my-dropdown
- %button{ type: 'button', data: { toggle: 'dropdown' }, 'aria-haspopup': true, 'aria-expanded': false }
- %span.dropdown-toggle-text
- Toggle Dropdown
- = icon('chevron-down')
-
- %ul.dropdown-menu
- %li
- %a
- item!
- ```
-
- Or use the helpers
- ```Haml
- .dropdown.my-dropdown
- = dropdown_toggle('Toogle!', { toggle: 'dropdown' })
- = dropdown_content
- %li
- %a
- item!
- ```
+ ```Haml
+ .dropdown.my-dropdown
+ %button{ type: 'button', data: { toggle: 'dropdown' }, 'aria-haspopup': true, 'aria-expanded': false }
+ %span.dropdown-toggle-text
+ Toggle Dropdown
+ = icon('chevron-down')
+
+ %ul.dropdown-menu
+ %li
+ %a
+ item!
+ ```
+
+ Or use the helpers
+
+ ```Haml
+ .dropdown.my-dropdown
+ = dropdown_toggle('Toogle!', { toggle: 'dropdown' })
+ = dropdown_content
+ %li
+ %a
+ item!
+ ```
[bootstrap-dropdowns]: https://getbootstrap.com/docs/3.3/javascript/#dropdowns
diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md
index 2628e95dbc1..676bce32998 100644
--- a/doc/development/fe_guide/performance.md
+++ b/doc/development/fe_guide/performance.md
@@ -30,8 +30,8 @@ To improve the time to first render we are using lazy loading for images. This w
the actual image source on the `data-src` attribute. After the HTML is rendered and JavaScript is loaded,
the value of `data-src` will be moved to `src` automatically if the image is in the current viewport.
-- Prepare images in HTML for lazy loading by renaming the `src` attribute to `data-src` AND adding the class `lazy`.
-- If you are using the Rails `image_tag` helper, all images will be lazy-loaded by default unless `lazy: false` is provided.
+- Prepare images in HTML for lazy loading by renaming the `src` attribute to `data-src` AND adding the class `lazy`.
+- If you are using the Rails `image_tag` helper, all images will be lazy-loaded by default unless `lazy: false` is provided.
If you are asynchronously adding content which contains lazy images then you need to call the function
`gl.lazyLoader.searchLazyImages()` which will search for lazy images and load them if needed.
@@ -96,26 +96,26 @@ bundle and included on the page.
DOM has loaded, you should attach an event handler to the `DOMContentLoaded`
event with:
- ```javascript
- import initMyWidget from './my_widget';
+ ```javascript
+ import initMyWidget from './my_widget';
- document.addEventListener('DOMContentLoaded', () => {
- initMyWidget();
- });
- ```
+ document.addEventListener('DOMContentLoaded', () => {
+ initMyWidget();
+ });
+ ```
- **Supporting Module Placement:**
- - If a class or a module is _specific to a particular route_, try to locate
- it close to the entry point it will be used. For instance, if
- `my_widget.js` is only imported within `pages/widget/show/index.js`, you
- should place the module at `pages/widget/show/my_widget.js` and import it
- with a relative path (e.g. `import initMyWidget from './my_widget';`).
- - If a class or module is _used by multiple routes_, place it within a
- shared directory at the closest common parent directory for the entry
- points that import it. For example, if `my_widget.js` is imported within
- both `pages/widget/show/index.js` and `pages/widget/run/index.js`, then
- place the module at `pages/widget/shared/my_widget.js` and import it with
- a relative path if possible (e.g. `../shared/my_widget`).
+ - If a class or a module is _specific to a particular route_, try to locate
+ it close to the entry point it will be used. For instance, if
+ `my_widget.js` is only imported within `pages/widget/show/index.js`, you
+ should place the module at `pages/widget/show/my_widget.js` and import it
+ with a relative path (e.g. `import initMyWidget from './my_widget';`).
+ - If a class or module is _used by multiple routes_, place it within a
+ shared directory at the closest common parent directory for the entry
+ points that import it. For example, if `my_widget.js` is imported within
+ both `pages/widget/show/index.js` and `pages/widget/run/index.js`, then
+ place the module at `pages/widget/shared/my_widget.js` and import it with
+ a relative path if possible (e.g. `../shared/my_widget`).
- **Enterprise Edition Caveats:**
For GitLab Enterprise Edition, page-specific entry points will override their
@@ -161,7 +161,7 @@ General tips:
- Use code-splitting dynamic imports wherever possible to lazy-load code that is not needed initially.
- [High Performance Animations][high-perf-animations]
--------
+---
## Additional Resources
diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md
index 18ef754642d..b0bbb4cc4b2 100644
--- a/doc/development/fe_guide/style_guide_js.md
+++ b/doc/development/fe_guide/style_guide_js.md
@@ -20,33 +20,33 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
1. **Never Ever EVER** disable eslint globally for a file
- ```javascript
- // bad
- /* eslint-disable */
+ ```javascript
+ // bad
+ /* eslint-disable */
- // better
- /* eslint-disable some-rule, some-other-rule */
+ // better
+ /* eslint-disable some-rule, some-other-rule */
- // best
- // nothing :)
- ```
+ // best
+ // nothing :)
+ ```
1. If you do need to disable a rule for a single violation, try to do it as locally as possible
- ```javascript
- // bad
- /* eslint-disable no-new */
+ ```javascript
+ // bad
+ /* eslint-disable no-new */
- import Foo from 'foo';
+ import Foo from 'foo';
- new Foo();
+ new Foo();
- // better
- import Foo from 'foo';
+ // better
+ import Foo from 'foo';
- // eslint-disable-next-line no-new
- new Foo();
- ```
+ // eslint-disable-next-line no-new
+ new Foo();
+ ```
1. There are few rules that we need to disable due to technical debt. Which are:
1. [no-new][eslint-new]
@@ -55,113 +55,113 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
1. When they are needed _always_ place ESlint directive comment blocks on the first line of a script,
followed by any global declarations, then a blank newline prior to any imports or code.
- ```javascript
- // bad
- /* global Foo */
- /* eslint-disable no-new */
- import Bar from './bar';
+ ```javascript
+ // bad
+ /* global Foo */
+ /* eslint-disable no-new */
+ import Bar from './bar';
- // good
- /* eslint-disable no-new */
- /* global Foo */
+ // good
+ /* eslint-disable no-new */
+ /* global Foo */
- import Bar from './bar';
- ```
+ import Bar from './bar';
+ ```
1. **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead.
1. When declaring multiple globals, always use one `/* global [name] */` line per variable.
- ```javascript
- // bad
- /* globals Flash, Cookies, jQuery */
+ ```javascript
+ // bad
+ /* globals Flash, Cookies, jQuery */
- // good
- /* global Flash */
- /* global Cookies */
- /* global jQuery */
- ```
+ // good
+ /* global Flash */
+ /* global Cookies */
+ /* global jQuery */
+ ```
1. Use up to 3 parameters for a function or class. If you need more accept an Object instead.
- ```javascript
- // bad
- fn(p1, p2, p3, p4) {}
+ ```javascript
+ // bad
+ fn(p1, p2, p3, p4) {}
- // good
- fn(options) {}
- ```
+ // good
+ fn(options) {}
+ ```
#### Modules, Imports, and Exports
1. Use ES module syntax to import modules
- ```javascript
- // bad
- const SomeClass = require('some_class');
+ ```javascript
+ // bad
+ const SomeClass = require('some_class');
- // good
- import SomeClass from 'some_class';
+ // good
+ import SomeClass from 'some_class';
- // bad
- module.exports = SomeClass;
+ // bad
+ module.exports = SomeClass;
- // good
- export default SomeClass;
- ```
+ // good
+ export default SomeClass;
+ ```
- Import statements are following usual naming guidelines, for example object literals use camel case:
+ Import statements are following usual naming guidelines, for example object literals use camel case:
- ```javascript
- // some_object file
- export default {
- key: 'value',
- };
+ ```javascript
+ // some_object file
+ export default {
+ key: 'value',
+ };
- // bad
- import ObjectLiteral from 'some_object';
+ // bad
+ import ObjectLiteral from 'some_object';
- // good
- import objectLiteral from 'some_object';
- ```
+ // good
+ import objectLiteral from 'some_object';
+ ```
1. Relative paths: when importing a module in the same directory, a child
directory, or an immediate parent directory prefer relative paths. When
importing a module which is two or more levels up, prefer either `~/` or `ee/`.
- In **app/assets/javascripts/my-feature/subdir**:
+ In **app/assets/javascripts/my-feature/subdir**:
- ```javascript
- // bad
- import Foo from '~/my-feature/foo';
- import Bar from '~/my-feature/subdir/bar';
- import Bin from '~/my-feature/subdir/lib/bin';
+ ```javascript
+ // bad
+ import Foo from '~/my-feature/foo';
+ import Bar from '~/my-feature/subdir/bar';
+ import Bin from '~/my-feature/subdir/lib/bin';
- // good
- import Foo from '../foo';
- import Bar from './bar';
- import Bin from './lib/bin';
- ```
+ // good
+ import Foo from '../foo';
+ import Bar from './bar';
+ import Bin from './lib/bin';
+ ```
- In **spec/javascripts**:
+ In **spec/javascripts**:
- ```javascript
- // bad
- import Foo from '../../app/assets/javascripts/my-feature/foo';
+ ```javascript
+ // bad
+ import Foo from '../../app/assets/javascripts/my-feature/foo';
- // good
- import Foo from '~/my-feature/foo';
- ```
+ // good
+ import Foo from '~/my-feature/foo';
+ ```
- When referencing an **EE component**:
+ When referencing an **EE component**:
- ```javascript
- // bad
- import Foo from '../../../../../ee/app/assets/javascripts/my-feature/ee-foo';
+ ```javascript
+ // bad
+ import Foo from '../../../../../ee/app/assets/javascripts/my-feature/ee-foo';
- // good
- import Foo from 'ee/my-feature/foo';
- ```
+ // good
+ import Foo from 'ee/my-feature/foo';
+ ```
1. Avoid using IIFE. Although we have a lot of examples of files which wrap their
contents in IIFEs (immediately-invoked function expressions),
@@ -170,136 +170,136 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
1. Avoid adding to the global namespace.
- ```javascript
- // bad
- window.MyClass = class { /* ... */ };
+ ```javascript
+ // bad
+ window.MyClass = class { /* ... */ };
- // good
- export default class MyClass { /* ... */ }
- ```
+ // good
+ export default class MyClass { /* ... */ }
+ ```
1. Side effects are forbidden in any script which contains export
- ```javascript
- // bad
- export default class MyClass { /* ... */ }
+ ```javascript
+ // bad
+ export default class MyClass { /* ... */ }
- document.addEventListener("DOMContentLoaded", function(event) {
- new MyClass();
- }
- ```
+ document.addEventListener("DOMContentLoaded", function(event) {
+ new MyClass();
+ }
+ ```
#### Data Mutation and Pure functions
1. Strive to write many small pure functions, and minimize where mutations occur.
- ```javascript
- // bad
- const values = {foo: 1};
+ ```javascript
+ // bad
+ const values = {foo: 1};
- function impureFunction(items) {
- const bar = 1;
+ function impureFunction(items) {
+ const bar = 1;
- items.foo = items.a * bar + 2;
+ items.foo = items.a * bar + 2;
- return items.a;
- }
+ return items.a;
+ }
- const c = impureFunction(values);
+ const c = impureFunction(values);
- // good
- var values = {foo: 1};
+ // good
+ var values = {foo: 1};
- function pureFunction (foo) {
- var bar = 1;
+ function pureFunction (foo) {
+ var bar = 1;
- foo = foo * bar + 2;
+ foo = foo * bar + 2;
- return foo;
- }
+ return foo;
+ }
- var c = pureFunction(values.foo);
+ var c = pureFunction(values.foo);
```
1. Avoid constructors with side-effects.
Although we aim for code without side-effects we need some side-effects for our code to run.
- If the class won't do anything if we only instantiate it, it's ok to add side effects into the constructor (_Note:_ The following is just an example. If the only purpose of the class is to add an event listener and handle the callback a function will be more suitable.)
-
- ```javascript
- // Bad
- export class Foo {
- constructor() {
- this.init();
- }
- init() {
- document.addEventListener('click', this.handleCallback)
- },
- handleCallback() {
-
- }
- }
-
- // Good
- export class Foo {
- constructor() {
- document.addEventListener()
- }
- handleCallback() {
- }
- }
- ```
-
- On the other hand, if a class only needs to extend a third party/add event listeners in some specific cases, they should be initialized outside of the constructor.
+ If the class won't do anything if we only instantiate it, it's ok to add side effects into the constructor (_Note:_ The following is just an example. If the only purpose of the class is to add an event listener and handle the callback a function will be more suitable.)
+
+ ```javascript
+ // Bad
+ export class Foo {
+ constructor() {
+ this.init();
+ }
+ init() {
+ document.addEventListener('click', this.handleCallback)
+ },
+ handleCallback() {
+
+ }
+ }
+
+ // Good
+ export class Foo {
+ constructor() {
+ document.addEventListener()
+ }
+ handleCallback() {
+ }
+ }
+ ```
+
+ On the other hand, if a class only needs to extend a third party/add event listeners in some specific cases, they should be initialized outside of the constructor.
1. Prefer `.map`, `.reduce` or `.filter` over `.forEach`
A forEach will most likely cause side effects, it will be mutating the array being iterated. Prefer using `.map`,
`.reduce` or `.filter`
- ```javascript
- const users = [ { name: 'Foo' }, { name: 'Bar' } ];
+ ```javascript
+ const users = [ { name: 'Foo' }, { name: 'Bar' } ];
- // bad
- users.forEach((user, index) => {
- user.id = index;
- });
+ // bad
+ users.forEach((user, index) => {
+ user.id = index;
+ });
- // good
- const usersWithId = users.map((user, index) => {
- return Object.assign({}, user, { id: index });
- });
- ```
+ // good
+ const usersWithId = users.map((user, index) => {
+ return Object.assign({}, user, { id: index });
+ });
+ ```
#### Parse Strings into Numbers
1. `parseInt()` is preferable over `Number()` or `+`
- ```javascript
- // bad
- +'10' // 10
+ ```javascript
+ // bad
+ +'10' // 10
- // good
- Number('10') // 10
+ // good
+ Number('10') // 10
- // better
- parseInt('10', 10);
- ```
+ // better
+ parseInt('10', 10);
+ ```
#### CSS classes used for JavaScript
1. If the class is being used in Javascript it needs to be prepend with `js-`
- ```html
- // bad
- <button class="add-user">
- Add User
- </button>
+ ```html
+ // bad
+ <button class="add-user">
+ Add User
+ </button>
- // good
- <button class="js-add-user">
- Add User
- </button>
- ```
+ // good
+ <button class="js-add-user">
+ Add User
+ </button>
+ ```
### Vue.js
@@ -314,43 +314,44 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
1. The store has it's own file
1. Use a function in the bundle file to instantiate the Vue component:
- ```javascript
- // bad
- class {
- init() {
- new Component({})
- }
- }
-
- // good
- document.addEventListener('DOMContentLoaded', () => new Vue({
- el: '#element',
- components: {
- componentName
- },
- render: createElement => createElement('component-name'),
- }));
- ```
+ ```javascript
+ // bad
+ class {
+ init() {
+ new Component({})
+ }
+ }
+
+ // good
+ document.addEventListener('DOMContentLoaded', () => new Vue({
+ el: '#element',
+ components: {
+ componentName
+ },
+ render: createElement => createElement('component-name'),
+ }));
+ ```
1. Do not use a singleton for the service or the store
- ```javascript
- // bad
- class Store {
- constructor() {
- if (!this.prototype.singleton) {
- // do something
- }
- }
- }
-
- // good
- class Store {
- constructor() {
- // do something
- }
- }
- ```
+ ```javascript
+ // bad
+ class Store {
+ constructor() {
+ if (!this.prototype.singleton) {
+ // do something
+ }
+ }
+ }
+
+ // good
+ class Store {
+ constructor() {
+ // do something
+ }
+ }
+ ```
+
1. Use `.vue` for Vue templates. Do not use `%template` in HAML.
#### Naming
@@ -358,38 +359,38 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
1. **Extensions**: Use `.vue` extension for Vue components. Do not use `.js` as file extension ([#34371]).
1. **Reference Naming**: Use PascalCase for their instances:
- ```javascript
- // bad
- import cardBoard from 'cardBoard.vue'
+ ```javascript
+ // bad
+ import cardBoard from 'cardBoard.vue'
- components: {
- cardBoard,
- };
+ components: {
+ cardBoard,
+ };
- // good
- import CardBoard from 'cardBoard.vue'
+ // good
+ import CardBoard from 'cardBoard.vue'
- components: {
- CardBoard,
- };
- ```
+ components: {
+ CardBoard,
+ };
+ ```
1. **Props Naming:** Avoid using DOM component prop names.
1. **Props Naming:** Use kebab-case instead of camelCase to provide props in templates.
- ```javascript
- // bad
- <component class="btn">
+ ```javascript
+ // bad
+ <component class="btn">
- // good
- <component css-class="btn">
+ // good
+ <component css-class="btn">
- // bad
- <component myProp="prop" />
+ // bad
+ <component myProp="prop" />
- // good
- <component my-prop="prop" />
- ```
+ // good
+ <component my-prop="prop" />
+ ```
[#34371]: https://gitlab.com/gitlab-org/gitlab-ce/issues/34371
@@ -399,205 +400,205 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
1. With more than one attribute, all attributes should be on a new line:
- ```javascript
- // bad
- <component v-if="bar"
- param="baz" />
+ ```javascript
+ // bad
+ <component v-if="bar"
+ param="baz" />
- <button class="btn">Click me</button>
+ <button class="btn">Click me</button>
- // good
- <component
- v-if="bar"
- param="baz"
- />
+ // good
+ <component
+ v-if="bar"
+ param="baz"
+ />
- <button class="btn">
- Click me
- </button>
- ```
+ <button class="btn">
+ Click me
+ </button>
+ ```
1. The tag can be inline if there is only one attribute:
- ```javascript
- // good
- <component bar="bar" />
+ ```javascript
+ // good
+ <component bar="bar" />
- // good
- <component
- bar="bar"
- />
+ // good
+ <component
+ bar="bar"
+ />
- // bad
- <component
- bar="bar" />
- ```
+ // bad
+ <component
+ bar="bar" />
+ ```
#### Quotes
1. Always use double quotes `"` inside templates and single quotes `'` for all other JS.
- ```javascript
- // bad
- template: `
- <button :class='style'>Button</button>
- `
+ ```javascript
+ // bad
+ template: `
+ <button :class='style'>Button</button>
+ `
- // good
- template: `
- <button :class="style">Button</button>
- `
- ```
+ // good
+ template: `
+ <button :class="style">Button</button>
+ `
+ ```
#### Props
1. Props should be declared as an object
- ```javascript
- // bad
- props: ['foo']
-
- // good
- props: {
- foo: {
- type: String,
- required: false,
- default: 'bar'
- }
- }
- ```
+ ```javascript
+ // bad
+ props: ['foo']
+
+ // good
+ props: {
+ foo: {
+ type: String,
+ required: false,
+ default: 'bar'
+ }
+ }
+ ```
1. Required key should always be provided when declaring a prop
- ```javascript
- // bad
- props: {
- foo: {
- type: String,
- }
- }
-
- // good
- props: {
- foo: {
- type: String,
- required: false,
- default: 'bar'
- }
- }
- ```
+ ```javascript
+ // bad
+ props: {
+ foo: {
+ type: String,
+ }
+ }
+
+ // good
+ props: {
+ foo: {
+ type: String,
+ required: false,
+ default: 'bar'
+ }
+ }
+ ```
1. Default key should be provided if the prop is not required.
_Note:_ There are some scenarios where we need to check for the existence of the property.
On those a default key should not be provided.
- ```javascript
- // good
- props: {
- foo: {
- type: String,
- required: false,
- }
- }
-
- // good
- props: {
- foo: {
- type: String,
- required: false,
- default: 'bar'
- }
- }
-
- // good
- props: {
- foo: {
- type: String,
- required: true
- }
- }
- ```
+ ```javascript
+ // good
+ props: {
+ foo: {
+ type: String,
+ required: false,
+ }
+ }
+
+ // good
+ props: {
+ foo: {
+ type: String,
+ required: false,
+ default: 'bar'
+ }
+ }
+
+ // good
+ props: {
+ foo: {
+ type: String,
+ required: true
+ }
+ }
+ ```
#### Data
1. `data` method should always be a function
- ```javascript
- // bad
- data: {
- foo: 'foo'
- }
-
- // good
- data() {
- return {
- foo: 'foo'
- };
- }
- ```
+ ```javascript
+ // bad
+ data: {
+ foo: 'foo'
+ }
+
+ // good
+ data() {
+ return {
+ foo: 'foo'
+ };
+ }
+ ```
#### Directives
1. Shorthand `@` is preferable over `v-on`
- ```javascript
- // bad
- <component v-on:click="eventHandler"/>
+ ```javascript
+ // bad
+ <component v-on:click="eventHandler"/>
- // good
- <component @click="eventHandler"/>
- ```
+ // good
+ <component @click="eventHandler"/>
+ ```
1. Shorthand `:` is preferable over `v-bind`
- ```javascript
- // bad
- <component v-bind:class="btn"/>
+ ```javascript
+ // bad
+ <component v-bind:class="btn"/>
- // good
- <component :class="btn"/>
- ```
+ // good
+ <component :class="btn"/>
+ ```
1. Shorthand `#` is preferable over `v-slot`
- ```javascript
- // bad
- <template v-slot:header></template>
+ ```javascript
+ // bad
+ <template v-slot:header></template>
- // good
- <template #header></template>
- ```
+ // good
+ <template #header></template>
+ ```
#### Closing tags
1. Prefer self closing component tags
- ```javascript
- // bad
- <component></component>
+ ```javascript
+ // bad
+ <component></component>
- // good
- <component />
- ```
+ // good
+ <component />
+ ```
#### Ordering
1. Tag order in `.vue` file
- ```
- <script>
- // ...
- </script>
-
- <template>
- // ...
- </template>
-
- // We don't use scoped styles but there are few instances of this
- <style>
- // ...
- </style>
- ```
+ ```
+ <script>
+ // ...
+ </script>
+
+ <template>
+ // ...
+ </template>
+
+ // We don't use scoped styles but there are few instances of this
+ <style>
+ // ...
+ </style>
+ ```
1. Properties in a Vue Component:
Check [order of properties in components rule][vue-order].
@@ -608,50 +609,50 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
1. If the elements of the array being iterated have an unique `id` it is advised to use it:
- ```html
- <div
- v-for="item in items"
- :key="item.id"
- >
- <!-- content -->
- </div>
- ```
+ ```html
+ <div
+ v-for="item in items"
+ :key="item.id"
+ >
+ <!-- content -->
+ </div>
+ ```
1. When the elements being iterated don't have a unique id, you can use the array index as the `:key` attribute
- ```html
- <div
- v-for="(item, index) in items"
- :key="index"
- >
- <!-- content -->
- </div>
- ```
+ ```html
+ <div
+ v-for="(item, index) in items"
+ :key="index"
+ >
+ <!-- content -->
+ </div>
+ ```
1. When using `v-for` with `template` and there is more than one child element, the `:key` values must be unique. It's advised to use `kebab-case` namespaces.
- ```html
- <template v-for="(item, index) in items">
- <span :key="`span-${index}`"></span>
- <button :key="`button-${index}`"></button>
- </template>
- ```
+ ```html
+ <template v-for="(item, index) in items">
+ <span :key="`span-${index}`"></span>
+ <button :key="`button-${index}`"></button>
+ </template>
+ ```
1. When dealing with nested `v-for` use the same guidelines as above.
- ```html
- <div
- v-for="item in items"
- :key="item.id"
- >
- <span
- v-for="element in array"
- :key="element.id"
- >
- <!-- content -->
- </span>
- </div>
- ```
+ ```html
+ <div
+ v-for="item in items"
+ :key="item.id"
+ >
+ <span
+ v-for="element in array"
+ :key="element.id"
+ >
+ <!-- content -->
+ </span>
+ </div>
+ ```
Useful links:
@@ -662,35 +663,35 @@ Useful links:
1. Tooltips: Do not rely on `has-tooltip` class name for Vue components
- ```javascript
- // bad
- <span
- class="has-tooltip"
- title="Some tooltip text">
- Text
- </span>
-
- // good
- <span
- v-tooltip
- title="Some tooltip text">
- Text
- </span>
- ```
+ ```javascript
+ // bad
+ <span
+ class="has-tooltip"
+ title="Some tooltip text">
+ Text
+ </span>
+
+ // good
+ <span
+ v-tooltip
+ title="Some tooltip text">
+ Text
+ </span>
+ ```
1. Tooltips: When using a tooltip, include the tooltip directive, `./app/assets/javascripts/vue_shared/directives/tooltip.js`
1. Don't change `data-original-title`.
- ```javascript
- // bad
- <span data-original-title="tooltip text">Foo</span>
+ ```javascript
+ // bad
+ <span data-original-title="tooltip text">Foo</span>
- // good
- <span title="tooltip text">Foo</span>
+ // good
+ <span title="tooltip text">Foo</span>
- $('span').tooltip('_fixTitle');
- ```
+ $('span').tooltip('_fixTitle');
+ ```
### The Javascript/Vue Accord
diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md
index bf248b7f8af..9eeaee4482f 100644
--- a/doc/development/fe_guide/vuex.md
+++ b/doc/development/fe_guide/vuex.md
@@ -1,15 +1,18 @@
# Vuex
+
To manage the state of an application you should use [Vuex][vuex-docs].
_Note:_ All of the below is explained in more detail in the official [Vuex documentation][vuex-docs].
## Separation of concerns
+
Vuex is composed of State, Getters, Mutations, Actions and Modules.
When a user clicks on an action, we need to `dispatch` it. This action will `commit` a mutation that will change the state.
_Note:_ The action itself will not update the state, only a mutation should update the state.
## File structure
+
When using Vuex at GitLab, separate this concerns into different files to improve readability:
```
@@ -21,10 +24,12 @@ When using Vuex at GitLab, separate this concerns into different files to improv
├── state.js # state
└── mutation_types.js # mutation types
```
+
The following example shows an application that lists and adds users to the state.
(For a more complex example implementation take a look at the security applications store in [here](https://gitlab.com/gitlab-org/gitlab-ee/tree/master/ee/app/assets/javascripts/vue_shared/security_reports/store))
### `index.js`
+
This is the entry point for our store. You can use the following as a guide:
```javascript
@@ -47,6 +52,7 @@ export default createStore();
```
### `state.js`
+
The first thing you should do before writing any code is to design the state.
Often we need to provide data from haml to our Vue application. Let's store it in the state for better access.
@@ -66,9 +72,11 @@ Often we need to provide data from haml to our Vue application. Let's store it i
```
#### Access `state` properties
+
You can use `mapState` to access state properties in the components.
### `actions.js`
+
An action is a payload of information to send data from our application to our store.
An action is usually composed by a `type` and a `payload` and they describe what happened.
@@ -110,6 +118,7 @@ In this file, we will write the actions that will call the respective mutations:
```
#### Actions Pattern: `request` and `receive` namespaces
+
When a request is made we often want to show a loading state to the user.
Instead of creating an action to toggle the loading state and dispatch it in the component,
@@ -136,6 +145,7 @@ By following this pattern we guarantee:
1. Actions are simple and straightforward
#### Dispatching actions
+
To dispatch an action from a component, use the `mapActions` helper:
```javascript
@@ -154,6 +164,7 @@ import { mapActions } from 'vuex';
```
### `mutations.js`
+
The mutations specify how the application state changes in response to actions sent to the store.
The only way to change state in a Vuex store should be by committing a mutation.
@@ -193,6 +204,7 @@ Remember that actions only describe that something happened, they don't describe
```
### `getters.js`
+
Sometimes we may need to get derived state based on store state, like filtering for a specific prop.
Using a getter will also cache the result based on dependencies due to [how computed props work](https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods)
This can be done through the `getters`:
@@ -219,6 +231,7 @@ import { mapGetters } from 'vuex';
```
### `mutation_types.js`
+
From [vuex mutations docs][vuex-mutations]:
> It is a commonly seen pattern to use constants for mutation types in various Flux implementations. This allows the code to take advantage of tooling like linters, and putting all constants in a single file allows your collaborators to get an at-a-glance view of what mutations are possible in the entire application.
@@ -227,6 +240,7 @@ export const ADD_USER = 'ADD_USER';
```
### How to include the store in your application
+
The store should be included in the main component of your application:
```javascript
@@ -241,6 +255,7 @@ The store should be included in the main component of your application:
```
### Communicating with the Store
+
```javascript
<script>
import { mapActions, mapState, mapGetters } from 'vuex';
@@ -298,29 +313,33 @@ export default {
1. Do not call a mutation directly. Always use an action to commit a mutation. Doing so will keep consistency throughout the application. From Vuex docs:
- > why don't we just call store.commit('action') directly? Well, remember that mutations must be synchronous? Actions aren't. We can perform asynchronous operations inside an action.
+ > why don't we just call store.commit('action') directly? Well, remember that mutations must be synchronous? Actions aren't. We can perform asynchronous operations inside an action.
- ```javascript
- // component.vue
+ ```javascript
+ // component.vue
- // bad
- created() {
- this.$store.commit('mutation');
- }
+ // bad
+ created() {
+ this.$store.commit('mutation');
+ }
+
+ // good
+ created() {
+ this.$store.dispatch('action');
+ }
+ ```
- // good
- created() {
- this.$store.dispatch('action');
- }
- ```
1. Use mutation types instead of hardcoding strings. It will be less error prone.
1. The State will be accessible in all components descending from the use where the store is instantiated.
### Testing Vuex
+
#### Testing Vuex concerns
+
Refer to [vuex docs][vuex-testing] regarding testing Actions, Getters and Mutations.
#### Testing components that need a store
+
Smaller components might use `store` properties to access the data.
In order to write unit tests for those components, we need to include the store and provide the correct state:
@@ -363,6 +382,7 @@ describe('component', () => {
```
#### Testing Vuex actions and getters
+
Because we're currently using [`babel-plugin-rewire`](https://github.com/speedskater/babel-plugin-rewire), you may encounter the following error when testing your Vuex actions and getters:
`[vuex] actions should be function or object with "handler" function`
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index 17462887162..141f5a8d6d9 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -21,18 +21,18 @@ The following tools are used:
1. [`gettext_i18n_rails`](https://github.com/grosser/gettext_i18n_rails): this
gem allow us to translate content from models, views and controllers. Also
it gives us access to the following raketasks:
- - `rake gettext:find`: Parses almost all the files from the
- Rails application looking for content that has been marked for
- translation. Finally, it updates the PO files with the new content that
- it has found.
- - `rake gettext:pack`: Processes the PO files and generates the
- MO files that are binary and are finally used by the application.
+ - `rake gettext:find`: Parses almost all the files from the
+ Rails application looking for content that has been marked for
+ translation. Finally, it updates the PO files with the new content that
+ it has found.
+ - `rake gettext:pack`: Processes the PO files and generates the
+ MO files that are binary and are finally used by the application.
1. [`gettext_i18n_rails_js`](https://github.com/webhippie/gettext_i18n_rails_js):
this gem is useful to make the translations available in JavaScript. It
provides the following raketask:
- - `rake gettext:po_to_json`: Reads the contents from the PO files and
- generates JSON files containing all the available translations.
+ - `rake gettext:po_to_json`: Reads the contents from the PO files and
+ generates JSON files containing all the available translations.
1. PO editor: there are multiple applications that can help us to work with PO
files, a good option is [Poedit](https://poedit.net/download) which is
@@ -139,60 +139,61 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s
- In Ruby/HAML:
- ```ruby
- _("Hello %{name}") % { name: 'Joe' } => 'Hello Joe'
- ```
+ ```ruby
+ _("Hello %{name}") % { name: 'Joe' } => 'Hello Joe'
+ ```
- In JavaScript:
- ```js
- import { __, sprintf } from '~/locale';
+ ```js
+ import { __, sprintf } from '~/locale';
- sprintf(__('Hello %{username}'), { username: 'Joe' }); // => 'Hello Joe'
- ```
+ sprintf(__('Hello %{username}'), { username: 'Joe' }); // => 'Hello Joe'
+ ```
- By default, `sprintf` escapes the placeholder values.
- If you want to take care of that yourself, you can pass `false` as third argument.
+ By default, `sprintf` escapes the placeholder values.
+ If you want to take care of that yourself, you can pass `false` as third argument.
- ```js
- import { __, sprintf } from '~/locale';
+ ```js
+ import { __, sprintf } from '~/locale';
- sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }); // => 'This is &lt;strong&gt;bold&lt;/strong&gt;'
- sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }, false); // => 'This is <strong>bold</strong>'
- ```
+ sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }); // => 'This is &lt;strong&gt;bold&lt;/strong&gt;'
+ sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }, false); // => 'This is <strong>bold</strong>'
+ ```
### Plurals
- In Ruby/HAML:
- ```ruby
- n_('Apple', 'Apples', 3)
- # => 'Apples'
- ```
+ ```ruby
+ n_('Apple', 'Apples', 3)
+ # => 'Apples'
+ ```
- Using interpolation:
- ```ruby
- n_("There is a mouse.", "There are %d mice.", size) % size
- # => When size == 1: 'There is a mouse.'
- # => When size == 2: 'There are 2 mice.'
- ```
+ Using interpolation:
- Avoid using `%d` or count variables in singular strings. This allows more natural translation in some languages.
+ ```ruby
+ n_("There is a mouse.", "There are %d mice.", size) % size
+ # => When size == 1: 'There is a mouse.'
+ # => When size == 2: 'There are 2 mice.'
+ ```
+
+ Avoid using `%d` or count variables in singular strings. This allows more natural translation in some languages.
- In JavaScript:
- ```js
- n__('Apple', 'Apples', 3)
- // => 'Apples'
- ```
+ ```js
+ n__('Apple', 'Apples', 3)
+ // => 'Apples'
+ ```
- Using interpolation:
+ Using interpolation:
- ```js
- n__('Last day', 'Last %d days', x)
- // => When x == 1: 'Last day'
- // => When x == 2: 'Last 2 days'
- ```
+ ```js
+ n__('Last day', 'Last %d days', x)
+ // => When x == 1: 'Last day'
+ // => When x == 2: 'Last 2 days'
+ ```
### Namespaces
@@ -202,17 +203,17 @@ Namespaces should be PascalCase.
- In Ruby/HAML:
- ```ruby
- s_('OpenedNDaysAgo|Opened')
- ```
+ ```ruby
+ s_('OpenedNDaysAgo|Opened')
+ ```
- In case the translation is not found it will return `Opened`.
+ In case the translation is not found it will return `Opened`.
- In JavaScript:
- ```js
- s__('OpenedNDaysAgo|Opened')
- ```
+ ```js
+ s__('OpenedNDaysAgo|Opened')
+ ```
Note: The namespace should be removed from the translation. See the [translation
guidelines for more details](translation.md#namespaced-strings).
@@ -235,12 +236,12 @@ This makes use of [`Intl.DateTimeFormat`].
- In Ruby/HAML, we have two ways of adding format to dates and times:
1. **Through the `l` helper**, i.e. `l(active_session.created_at, format: :short)`. We have some predefined formats for
- [dates](https://gitlab.com/gitlab-org/gitlab-ce/blob/v11.7.0/config/locales/en.yml#L54) and [times](https://gitlab.com/gitlab-org/gitlab-ce/blob/v11.7.0/config/locales/en.yml#L261).
- If you need to add a new format, because other parts of the code could benefit from it,
- you'll need to add it to [en.yml](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/locales/en.yml) file.
+ [dates](https://gitlab.com/gitlab-org/gitlab-ce/blob/v11.7.0/config/locales/en.yml#L54) and [times](https://gitlab.com/gitlab-org/gitlab-ce/blob/v11.7.0/config/locales/en.yml#L261).
+ If you need to add a new format, because other parts of the code could benefit from it,
+ you'll need to add it to [en.yml](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/locales/en.yml) file.
1. **Through `strftime`**, i.e. `milestone.start_date.strftime('%b %-d')`. We use `strftime` in case none of the formats
- defined on [en.yml](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/locales/en.yml) matches the date/time
- specifications we need, and if there is no need to add it as a new format because is very particular (i.e. it's only used in a single view).
+ defined on [en.yml](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/locales/en.yml) matches the date/time
+ specifications we need, and if there is no need to add it as a new format because is very particular (i.e. it's only used in a single view).
## Best practices
@@ -268,40 +269,40 @@ should be externalized as follows:
This also applies when using links in between translated sentences, otherwise these texts are not translatable in certain languages.
- In Ruby/HAML, instead of:
-
- ```haml
- - zones_link = link_to(s_('ClusterIntegration|zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
- = s_('ClusterIntegration|Learn more about %{zones_link}').html_safe % { zones_link: zones_link }
- ```
-
- Set the link starting and ending HTML fragments as variables like so:
-
- ```haml
- - zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
- - zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url }
- = s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
- ```
+
+ ```haml
+ - zones_link = link_to(s_('ClusterIntegration|zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
+ = s_('ClusterIntegration|Learn more about %{zones_link}').html_safe % { zones_link: zones_link }
+ ```
+
+ Set the link starting and ending HTML fragments as variables like so:
+
+ ```haml
+ - zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
+ - zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url }
+ = s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
+ ```
- In JavaScript, instead of:
- ```js
- {{
- sprintf(s__("ClusterIntegration|Learn more about %{link}"), {
- link: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">zones</a>'
- })
- }}
- ```
-
- Set the link starting and ending HTML fragments as variables like so:
-
- ```js
- {{
- sprintf(s__("ClusterIntegration|Learn more about %{linkStart}zones%{linkEnd}"), {
- linkStart: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">'
- linkEnd: '</a>',
- })
- }}
- ```
+ ```js
+ {{
+ sprintf(s__("ClusterIntegration|Learn more about %{link}"), {
+ link: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">zones</a>'
+ })
+ }}
+ ```
+
+ Set the link starting and ending HTML fragments as variables like so:
+
+ ```js
+ {{
+ sprintf(s__("ClusterIntegration|Learn more about %{linkStart}zones%{linkEnd}"), {
+ linkStart: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">'
+ linkEnd: '</a>',
+ })
+ }}
+ ```
The reasoning behind this is that in some languages words change depending on context. For example in Japanese は is added to the subject of a sentence and を to the object. This is impossible to translate correctly if we extract individual words from the sentence.
@@ -374,29 +375,29 @@ Let's suppose you want to add translations for a new language, let's say French.
1. The first step is to register the new language in `lib/gitlab/i18n.rb`:
- ```ruby
- ...
- AVAILABLE_LANGUAGES = {
- ...,
- 'fr' => 'Français'
- }.freeze
- ...
- ```
+ ```ruby
+ ...
+ AVAILABLE_LANGUAGES = {
+ ...,
+ 'fr' => 'Français'
+ }.freeze
+ ...
+ ```
1. Next, you need to add the language:
- ```sh
- bin/rake gettext:add_language[fr]
- ```
+ ```sh
+ bin/rake gettext:add_language[fr]
+ ```
- If you want to add a new language for a specific region, the command is similar,
- you just need to separate the region with an underscore (`_`). For example:
+ If you want to add a new language for a specific region, the command is similar,
+ you just need to separate the region with an underscore (`_`). For example:
- ```sh
- bin/rake gettext:add_language[en_GB]
- ```
+ ```sh
+ bin/rake gettext:add_language[en_GB]
+ ```
- Please note that you need to specify the region part in capitals.
+ Please note that you need to specify the region part in capitals.
1. Now that the language is added, a new directory has been created under the
path: `locale/fr/`. You can now start using your PO editor to edit the PO file
@@ -406,9 +407,9 @@ Let's suppose you want to add translations for a new language, let's say French.
in order to generate the binary MO files and finally update the JSON files
containing the translations:
- ```sh
- bin/rake gettext:compile
- ```
+ ```sh
+ bin/rake gettext:compile
+ ```
1. In order to see the translated content we need to change our preferred language
which can be found under the user's **Settings** (`/profile`).
@@ -416,7 +417,7 @@ Let's suppose you want to add translations for a new language, let's say French.
1. After checking that the changes are ok, you can proceed to commit the new files.
For example:
- ```sh
- git add locale/fr/ app/assets/javascripts/locale/fr/
- git commit -m "Add French translations for Cycle Analytics page"
- ```
+ ```sh
+ git add locale/fr/ app/assets/javascripts/locale/fr/
+ git commit -m "Add French translations for Cycle Analytics page"
+ ```
diff --git a/doc/development/utilities.md b/doc/development/utilities.md
index 0e396baccff..4021756343c 100644
--- a/doc/development/utilities.md
+++ b/doc/development/utilities.md
@@ -6,44 +6,44 @@ We developed a number of utilities to ease development.
- Deep merges an array of hashes:
- ``` ruby
- Gitlab::Utils::MergeHash.merge(
- [{ hello: ["world"] },
- { hello: "Everyone" },
- { hello: { greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] } },
- "Goodbye", "Hallo"]
- )
- ```
-
- Gives:
-
- ``` ruby
- [
- {
- hello:
- [
- "world",
- "Everyone",
- { greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] }
- ]
- },
- "Goodbye"
- ]
- ```
+ ``` ruby
+ Gitlab::Utils::MergeHash.merge(
+ [{ hello: ["world"] },
+ { hello: "Everyone" },
+ { hello: { greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] } },
+ "Goodbye", "Hallo"]
+ )
+ ```
+
+ Gives:
+
+ ``` ruby
+ [
+ {
+ hello:
+ [
+ "world",
+ "Everyone",
+ { greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] }
+ ]
+ },
+ "Goodbye"
+ ]
+ ```
- Extracts all keys and values from a hash into an array:
- ``` ruby
- Gitlab::Utils::MergeHash.crush(
- { hello: "world", this: { crushes: ["an entire", "hash"] } }
- )
- ```
+ ``` ruby
+ Gitlab::Utils::MergeHash.crush(
+ { hello: "world", this: { crushes: ["an entire", "hash"] } }
+ )
+ ```
- Gives:
+ Gives:
- ``` ruby
- [:hello, "world", :this, :crushes, "an entire", "hash"]
- ```
+ ``` ruby
+ [:hello, "world", :this, :crushes, "an entire", "hash"]
+ ```
## [`Override`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/utils/override.rb)
@@ -53,9 +53,9 @@ We developed a number of utilities to ease development.
`ENV['STATIC_VERIFICATION']` is set to avoid production runtime overhead.
This is useful to check:
- - If we have typos in overriding methods.
- - If we renamed the overridden methods, making original overriding methods
- overrides nothing.
+ - If we have typos in overriding methods.
+ - If we renamed the overridden methods, making original overriding methods
+ overrides nothing.
Here's a simple example:
@@ -94,47 +94,47 @@ We developed a number of utilities to ease development.
- Memoize the value even if it is `nil` or `false`.
- We often do `@value ||= compute`, however this doesn't work well if
- `compute` might eventually give `nil` and we don't want to compute again.
- Instead we could use `defined?` to check if the value is set or not.
- However it's tedious to write such pattern, and `StrongMemoize` would
- help us use such pattern.
+ We often do `@value ||= compute`, however this doesn't work well if
+ `compute` might eventually give `nil` and we don't want to compute again.
+ Instead we could use `defined?` to check if the value is set or not.
+ However it's tedious to write such pattern, and `StrongMemoize` would
+ help us use such pattern.
- Instead of writing patterns like this:
+ Instead of writing patterns like this:
- ``` ruby
- class Find
- def result
- return @result if defined?(@result)
+ ``` ruby
+ class Find
+ def result
+ return @result if defined?(@result)
- @result = search
- end
+ @result = search
end
- ```
+ end
+ ```
- We could write it like:
+ We could write it like:
- ``` ruby
- class Find
- include Gitlab::Utils::StrongMemoize
+ ``` ruby
+ class Find
+ include Gitlab::Utils::StrongMemoize
- def result
- strong_memoize(:result) do
- search
- end
+ def result
+ strong_memoize(:result) do
+ search
end
end
- ```
+ end
+ ```
- Clear memoization
- ``` ruby
- class Find
- include Gitlab::Utils::StrongMemoize
- end
+ ``` ruby
+ class Find
+ include Gitlab::Utils::StrongMemoize
+ end
- Find.new.clear_memoization(:result)
- ```
+ Find.new.clear_memoization(:result)
+ ```
## [`RequestCache`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/cache/request_cache.rb)
diff --git a/doc/topics/git/numerous_undo_possibilities_in_git/index.md b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
index 84201e11831..5cae532bf54 100644
--- a/doc/topics/git/numerous_undo_possibilities_in_git/index.md
+++ b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
@@ -110,21 +110,21 @@ At this point there are 3 options to undo the local changes you have:
- Discard all local changes, but save them for possible re-use [later](#quickly-save-local-changes):
- ```shell
- git stash
- ```
+ ```shell
+ git stash
+ ```
- Discarding local changes (permanently) to a file:
- ```shell
- git checkout -- <file>
- ```
+ ```shell
+ git checkout -- <file>
+ ```
- Discard all local changes to all files permanently:
- ```shell
- git reset --hard
- ```
+ ```shell
+ git reset --hard
+ ```
Before executing `git reset --hard`, keep in mind that there is also a way to
just temporary store the changes without committing them using `git stash`.
@@ -182,27 +182,27 @@ Now you have 4 options to undo your changes:
- Unstage the file to current commit (HEAD):
- ```shell
- git reset HEAD <file>
- ```
+ ```shell
+ git reset HEAD <file>
+ ```
- Unstage everything - retain changes:
- ```shell
- git reset
- ```
+ ```shell
+ git reset
+ ```
- Discard all local changes, but save them for [later](#quickly-save-local-changes):
- ```shell
- git stash
- ```
+ ```shell
+ git stash
+ ```
- Discard everything permanently:
- ```shell
- git reset --hard
- ```
+ ```shell
+ git reset --hard
+ ```
## Committed local changes
@@ -240,21 +240,21 @@ In our example we will end up with commit `B`, that introduced bug/error. We hav
- Undo (swap additions and deletions) changes introduced by commit `B`:
- ```shell
- git revert commit-B-id
- ```
+ ```shell
+ git revert commit-B-id
+ ```
- Undo changes on a single file or directory from commit `B`, but retain them in the staged state:
- ```shell
- git checkout commit-B-id <file>
- ```
+ ```shell
+ git checkout commit-B-id <file>
+ ```
- Undo changes on a single file or directory from commit `B`, but retain them in the unstaged state:
- ```shell
- git reset commit-B-id <file>
- ```
+ ```shell
+ git reset commit-B-id <file>
+ ```
- There is one command we also must not forget: **creating a new branch**
from the point where changes are not applicable or where the development has hit a
@@ -270,14 +270,14 @@ In our example we will end up with commit `B`, that introduced bug/error. We hav
you can [cherry-pick](../../../user/project/merge_requests/cherry_pick_changes.md#cherry-picking-a-commit)
that commit into a new merge request.
- ![Create a new branch to avoid clashing](img/branching.png)
+ ![Create a new branch to avoid clashing](img/branching.png)
- ```shell
- git checkout commit-B-id
- git checkout -b new-path-of-feature
- # Create <commit F>
- git commit -a
- ```
+ ```shell
+ git checkout commit-B-id
+ git checkout -b new-path-of-feature
+ # Create <commit F>
+ git commit -a
+ ```
### With history modification
@@ -297,9 +297,9 @@ delete commit `B`.
- Rebase the range from current commit D to A:
- ```shell
- git rebase -i A
- ```
+ ```shell
+ git rebase -i A
+ ```
- Command opens your favorite editor where you write `drop` in front of commit
`B`, but you leave default `pick` with all other commits. Save and exit the
@@ -310,9 +310,9 @@ In case you want to modify something introduced in commit `B`.
- Rebase the range from current commit D to A:
- ```shell
- git rebase -i A
- ```
+ ```shell
+ git rebase -i A
+ ```
- Command opens your favorite text editor where you write `edit` in front of commit
`B`, but leave default `pick` with all other commits. Save and exit the editor to
@@ -320,9 +320,9 @@ In case you want to modify something introduced in commit `B`.
- Now do your edits and commit changes:
- ```shell
- git commit -a
- ```
+ ```shell
+ git commit -a
+ ```
You can find some more examples in [below section where we explain how to modify
history](#how-modifying-history-is-done)
diff --git a/doc/topics/git/troubleshooting_git.md b/doc/topics/git/troubleshooting_git.md
index 417d91bf834..11284da30af 100644
--- a/doc/topics/git/troubleshooting_git.md
+++ b/doc/topics/git/troubleshooting_git.md
@@ -51,11 +51,11 @@ Configuring *both* the client and the server is unnecessary.
- On UNIX, edit `~/.ssh/config` (create the file if it doesn’t exist) and
add or edit:
- ```text
- Host your-gitlab-instance-url.com
- ServerAliveInterval 60
- ServerAliveCountMax 5
- ```
+ ```text
+ Host your-gitlab-instance-url.com
+ ServerAliveInterval 60
+ ServerAliveCountMax 5
+ ```
- On Windows, if you are using PuTTY, go to your session properties, then
navigate to "Connection" and under "Sending of null packets to keep
diff --git a/doc/university/training/end-user/README.md b/doc/university/training/end-user/README.md
index 99fb5e83387..423ba1cfbd7 100644
--- a/doc/university/training/end-user/README.md
+++ b/doc/university/training/end-user/README.md
@@ -54,6 +54,7 @@ project.
---
## Git Setup
+
Workshop Time!
---
@@ -88,7 +89,7 @@ git config --global --list
```
- You might want or be required to use an SSH key.
- - Instructions: [SSH](http://doc.gitlab.com/ce/ssh/README.html)
+ - Instructions: [SSH](http://doc.gitlab.com/ce/ssh/README.html)
---
@@ -119,13 +120,13 @@ cd ~/workspace
### Git Workflow
- Untracked files
- - New files that Git has not been told to track previously.
+ - New files that Git has not been told to track previously.
- Working area (Workspace)
- - Files that have been modified but are not committed.
+ - Files that have been modified but are not committed.
- Staging area (Index)
- - Modified files that have been marked to go in the next commit.
+ - Modified files that have been marked to go in the next commit.
- Upstream
- - Hosted repository on a shared server
+ - Hosted repository on a shared server
---
@@ -229,8 +230,6 @@ git push origin squash_some_bugs
---
-### Feedback and Collaboration
-
- Review the Thoughtbot code-review guide for suggestions to follow when reviewing merge requests:[Thoughtbot](https://github.com/thoughtbot/guides/tree/master/code-review)
- See GitLab merge requests for examples: [Merge Requests](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests)
@@ -266,20 +265,22 @@ git push origin squash_some_bugs
### Example 1/2
- git checkout -b conflicts_branch
+```sh
+git checkout -b conflicts_branch
- # vi conflicts.rb
- # Add 'Line4' and 'Line5'
+# vi conflicts.rb
+# Add 'Line4' and 'Line5'
- git commit -am "add line4 and line5"
- git push origin conflicts_branch
+git commit -am "add line4 and line5"
+git push origin conflicts_branch
- git checkout master
+git checkout master
- # vi conflicts.rb
- # Add 'Line6' and 'Line7'
- git commit -am "add line6 and line7"
- git push origin master
+# vi conflicts.rb
+# Add 'Line6' and 'Line7'
+git commit -am "add line6 and line7"
+git push origin master
+```
---
@@ -287,20 +288,22 @@ git push origin squash_some_bugs
Create a merge request on the GitLab web UI. You'll see a conflict warning.
- git checkout conflicts_branch
- git fetch
- git rebase master
+```sh
+git checkout conflicts_branch
+git fetch
+git rebase master
- # Fix conflicts by editing the files.
+# Fix conflicts by editing the files.
- git add conflicts.rb
- # No need to commit this file
+git add conflicts.rb
+# No need to commit this file
- git rebase --continue
+git rebase --continue
- # Remember that we have rewritten our commit history so we
- # need to force push so that our remote branch is restructured
- git push origin conflicts_branch -f
+# Remember that we have rewritten our commit history so we
+# need to force push so that our remote branch is restructured
+git push origin conflicts_branch -f
+```
---
@@ -321,20 +324,28 @@ Create a merge request on the GitLab web UI. You'll see a conflict warning.
To remove files from stage use reset HEAD. Where HEAD is the last commit of the current branch:
- git reset HEAD <file>
+```sh
+git reset HEAD <file>
+```
This will unstage the file but maintain the modifications. To revert the file back to the state it was in before the changes we can use:
- git checkout -- <file>
+```sh
+git checkout -- <file>
+```
To remove a file from disk and repo use 'git rm' and to rm a dir use the '-r' flag:
- git rm '*.txt'
- git rm -r <dirname>
+```sh
+git rm '*.txt'
+git rm -r <dirname>
+```
If we want to remove a file from the repository but keep it on disk, say we forgot to add it to our .gitignore file then use `--cache`:
- git rm <filename> --cache
+```sh
+git rm <filename> --cache
+```
---
@@ -342,19 +353,27 @@ If we want to remove a file from the repository but keep it on disk, say we forg
Undo last commit putting everything back into the staging area:
- git reset --soft HEAD^
+```sh
+git reset --soft HEAD^
+```
Add files and change message with:
- git commit --amend -m "New Message"
+```sh
+git commit --amend -m "New Message"
+```
Undo last and remove changes
- git reset --hard HEAD^
+```sh
+git reset --hard HEAD^
+```
Same as last one but for two commits back:
- git reset --hard HEAD^^
+```sh
+git reset --hard HEAD^^
+```
Don't reset after pushing
@@ -373,35 +392,38 @@ Don't reset after pushing
1. Pull for updates
1. Push changes
-----
+---
- # Change file edit_this_file.rb
- git status
- git commit -am "kjkfjkg"
- git log
- git commit --amend -m "New comment added"
- git log
- git reset --soft HEAD^
- git log
- git pull origin master
- git push origin master
+```sh
+# Change file edit_this_file.rb
+git status
+git commit -am "kjkfjkg"
+git log
+git commit --amend -m "New comment added"
+git log
+git reset --soft HEAD^
+git log
+git pull origin master
+git push origin master
+```
---
-### Note
+### git revert vs git reset
-git revert vs git reset
Reset removes the commit while revert removes the changes but leaves the commit
Revert is safer considering we can revert a revert
- # Changed file
- git commit -am "bug introduced"
- git revert HEAD
- # New commit created reverting changes
- # Now we want to re apply the reverted commit
- git log # take hash from the revert commit
- git revert <rev commit hash>
- # reverted commit is back (new commit created again)
+```sh
+# Changed file
+git commit -am "bug introduced"
+git revert HEAD
+# New commit created reverting changes
+# Now we want to re apply the reverted commit
+git log # take hash from the revert commit
+git revert <rev commit hash>
+# reverted commit is back (new commit created again)
+```
---
@@ -415,11 +437,11 @@ Revert is safer considering we can revert a revert
### Version Control
- - Local VCS was used with a filesystem or a simple db.
- - Centralized VCS such as Subversion includes collaboration but
- still is prone to data loss as the main server is the single point of
- failure.
- - Distributed VCS enables the team to have a complete copy of the project
- and work with little dependency to the main server. In case of a main
- server failing the project can be recovered by any of the latest copies
- from the team
+- Local VCS was used with a filesystem or a simple db.
+- Centralized VCS such as Subversion includes collaboration but
+ still is prone to data loss as the main server is the single point of
+ failure.
+- Distributed VCS enables the team to have a complete copy of the project
+ and work with little dependency to the main server. In case of a main
+ server failing the project can be recovered by any of the latest copies
+ from the team
diff --git a/doc/university/training/topics/git_add.md b/doc/university/training/topics/git_add.md
index 4c61d5eb175..7152fc2030b 100644
--- a/doc/university/training/topics/git_add.md
+++ b/doc/university/training/topics/git_add.md
@@ -10,32 +10,32 @@ Adds content to the index or staging area.
- Adds a list of file:
- ```bash
- git add <files>
- ```
+ ```bash
+ git add <files>
+ ```
- Adds all files including deleted ones:
- ```bash
- git add -A
- ```
+ ```bash
+ git add -A
+ ```
## Git add continued
- Add all text files in current dir:
- ```bash
- git add *.txt
- ```
+ ```bash
+ git add *.txt
+ ```
- Add all text file in the project:
- ```bash
- git add "*.txt*"
- ```
+ ```bash
+ git add "*.txt*"
+ ```
- Adds all files in directory:
- ```bash
- git add views/layouts/
- ```
+ ```bash
+ git add views/layouts/
+ ```
diff --git a/doc/university/training/topics/git_log.md b/doc/university/training/topics/git_log.md
index 11addcd3ee1..bae734554f5 100644
--- a/doc/university/training/topics/git_log.md
+++ b/doc/university/training/topics/git_log.md
@@ -8,33 +8,33 @@ Git log lists commit history. It allows searching and filtering.
- Initiate log:
- ```sh
- git log
- ```
+ ```sh
+ git log
+ ```
- Retrieve set number of records:
- ```sh
- git log -n 2
- ```
+ ```sh
+ git log -n 2
+ ```
- Search commits by author. Allows user name or a regular expression.
- ```sh
- git log --author="user_name"
- ```
+ ```sh
+ git log --author="user_name"
+ ```
- Search by comment message:
- ```sh
- git log --grep="<pattern>"
- ```
+ ```sh
+ git log --grep="<pattern>"
+ ```
- Search by date:
- ```sh
- git log --since=1.month.ago --until=3.weeks.ago
- ```
+ ```sh
+ git log --since=1.month.ago --until=3.weeks.ago
+ ```
## Git Log Workflow
diff --git a/doc/university/training/topics/rollback_commits.md b/doc/university/training/topics/rollback_commits.md
index 1e6602deef2..c17e8d59737 100644
--- a/doc/university/training/topics/rollback_commits.md
+++ b/doc/university/training/topics/rollback_commits.md
@@ -8,29 +8,29 @@ comments: false
- Undo last commit putting everything back into the staging area:
- ```sh
- git reset --soft HEAD^
- ```
+ ```sh
+ git reset --soft HEAD^
+ ```
- Add files and change message with:
- ```sh
- git commit --amend -m "New Message"
- ```
+ ```sh
+ git commit --amend -m "New Message"
+ ```
- Undo last and remove changes:
- ```sh
- git reset --hard HEAD^
- ```
+ ```sh
+ git reset --hard HEAD^
+ ```
- Same as last one but for two commits back:
- ```sh
- git reset --hard HEAD^^
- ```
+ ```sh
+ git reset --hard HEAD^^
+ ```
-** Don't reset after pushing **
+**Don't reset after pushing**
## Reset Workflow
diff --git a/doc/university/training/topics/stash.md b/doc/university/training/topics/stash.md
index 02b2f610266..21abad88cfa 100644
--- a/doc/university/training/topics/stash.md
+++ b/doc/university/training/topics/stash.md
@@ -9,47 +9,47 @@ and we need to change to a different branch.
- Stash:
- ```sh
- git stash save
- # or
- git stash
- # or with a message
- git stash save "this is a message to display on the list"
- ```
+ ```sh
+ git stash save
+ # or
+ git stash
+ # or with a message
+ git stash save "this is a message to display on the list"
+ ```
- Apply stash to keep working on it:
- ```sh
- git stash apply
- # or apply a specific one from out stack
- git stash apply stash@{3}
- ```
+ ```sh
+ git stash apply
+ # or apply a specific one from out stack
+ git stash apply stash@{3}
+ ```
- Every time we save a stash it gets stacked so by using list we can see all our
stashes.
- ```sh
- git stash list
- # or for more information (log methods)
- git stash list --stat
- ```
+ ```sh
+ git stash list
+ # or for more information (log methods)
+ git stash list --stat
+ ```
- To clean our stack we need to manually remove them:
- ```sh
- # drop top stash
- git stash drop
- # or
- git stash drop <name>
- # to clear all history we can use
- git stash clear
- ```
+ ```sh
+ # drop top stash
+ git stash drop
+ # or
+ git stash drop <name>
+ # to clear all history we can use
+ git stash clear
+ ```
- Apply and drop on one command:
- ```sh
- git stash pop
- ```
+ ```sh
+ git stash pop
+ ```
- If we meet conflicts we need to either reset or commit our changes.
- Conflicts through `pop` will not drop a stash afterwards.
diff --git a/doc/university/training/topics/unstage.md b/doc/university/training/topics/unstage.md
index af16afdc5d1..fa1f63f9ec4 100644
--- a/doc/university/training/topics/unstage.md
+++ b/doc/university/training/topics/unstage.md
@@ -6,27 +6,27 @@ comments: false
## Unstage
-- To remove files from stage use reset HEAD where HEAD is the last commit of the current branch. This will unstage the file but maintain the modifications.
+- To remove files from stage use reset HEAD where HEAD is the last commit of the current branch. This will unstage the file but maintain the modifications.
- ```bash
- git reset HEAD <file>
- ```
+ ```bash
+ git reset HEAD <file>
+ ```
- To revert the file back to the state it was in before the changes we can use:
- ```bash
- git checkout -- <file>
- ```
+ ```bash
+ git checkout -- <file>
+ ```
- To remove a file from disk and repo use 'git rm' and to rm a dir use the '-r' flag:
- ```sh
- git rm '*.txt'
- git rm -r <dirname>
- ```
+ ```sh
+ git rm '*.txt'
+ git rm -r <dirname>
+ ```
- If we want to remove a file from the repository but keep it on disk, say we forgot to add it to our `.gitignore` file then use `--cache`:
- ```sh
- git rm <filename> --cache
- ```
+ ```sh
+ git rm <filename> --cache
+ ```
diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md
index 1e424134242..f6a1b6abdbf 100644
--- a/doc/update/mysql_to_postgresql.md
+++ b/doc/update/mysql_to_postgresql.md
@@ -72,15 +72,15 @@ need to enable the bundled PostgreSQL:
1. Stop GitLab:
- ```bash
- sudo gitlab-ctl stop
- ```
+ ```bash
+ sudo gitlab-ctl stop
+ ```
1. Edit `/etc/gitlab/gitlab.rb` to enable bundled PostgreSQL:
- ```
- postgresql['enable'] = true
- ```
+ ```
+ postgresql['enable'] = true
+ ```
1. Edit `/etc/gitlab/gitlab.rb` to use the bundled PostgreSQL. Please check
all the settings beginning with `db_`, such as `gitlab_rails['db_adapter']`
@@ -91,22 +91,22 @@ need to enable the bundled PostgreSQL:
for the changes to take effect.
1. Start Unicorn and PostgreSQL so that we can prepare the schema:
- ```bash
- sudo gitlab-ctl start unicorn
- sudo gitlab-ctl start postgresql
- ```
+ ```bash
+ sudo gitlab-ctl start unicorn
+ sudo gitlab-ctl start postgresql
+ ```
1. Run the following commands to prepare the schema:
- ```bash
- sudo gitlab-rake db:create db:migrate
- ```
+ ```bash
+ sudo gitlab-rake db:create db:migrate
+ ```
1. Stop Unicorn to prevent other database access from interfering with the loading of data:
- ```bash
- sudo gitlab-ctl stop unicorn
- ```
+ ```bash
+ sudo gitlab-ctl stop unicorn
+ ```
After these steps, you'll have a fresh PostgreSQL database with up-to-date schema.
@@ -116,57 +116,57 @@ new PostgreSQL one:
1. Save the following snippet in a `commands.load` file, and edit with your
MySQL database `username`, `password` and `host`:
- ```
- LOAD DATABASE
- FROM mysql://username:password@host/gitlabhq_production
- INTO postgresql://gitlab-psql@unix://var/opt/gitlab/postgresql:/gitlabhq_production
+ ```
+ LOAD DATABASE
+ FROM mysql://username:password@host/gitlabhq_production
+ INTO postgresql://gitlab-psql@unix://var/opt/gitlab/postgresql:/gitlabhq_production
- WITH include no drop, truncate, disable triggers, create no tables,
- create no indexes, preserve index names, no foreign keys,
- data only
+ WITH include no drop, truncate, disable triggers, create no tables,
+ create no indexes, preserve index names, no foreign keys,
+ data only
- ALTER SCHEMA 'gitlabhq_production' RENAME TO 'public'
+ ALTER SCHEMA 'gitlabhq_production' RENAME TO 'public'
- ;
- ```
+ ;
+ ```
1. Start the migration:
- ```bash
- sudo -u gitlab-psql pgloader commands.load
- ```
+ ```bash
+ sudo -u gitlab-psql pgloader commands.load
+ ```
1. Once the migration finishes, you should see a summary table that looks like
the following:
- ```
- table name read imported errors total time
- ----------------------------------------------- --------- --------- --------- --------------
- fetch meta data 119 119 0 0.388s
- Truncate 119 119 0 1.134s
- ----------------------------------------------- --------- --------- --------- --------------
- public.abuse_reports 0 0 0 0.490s
- public.appearances 0 0 0 0.488s
- .
- .
- .
- public.web_hook_logs 0 0 0 1.080s
- ----------------------------------------------- --------- --------- --------- --------------
- COPY Threads Completion 4 4 0 2.008s
- Reset Sequences 113 113 0 0.304s
- Install Comments 0 0 0 0.000s
- ----------------------------------------------- --------- --------- --------- --------------
- Total import time 1894 1894 0 12.497s
- ```
-
- If there is no output for more than 30 minutes, it's possible `pgloader` encountered an error. See
- the [troubleshooting guide](#troubleshooting) for more details.
+ ```
+ table name read imported errors total time
+ ----------------------------------------------- --------- --------- --------- --------------
+ fetch meta data 119 119 0 0.388s
+ Truncate 119 119 0 1.134s
+ ----------------------------------------------- --------- --------- --------- --------------
+ public.abuse_reports 0 0 0 0.490s
+ public.appearances 0 0 0 0.488s
+ .
+ .
+ .
+ public.web_hook_logs 0 0 0 1.080s
+ ----------------------------------------------- --------- --------- --------- --------------
+ COPY Threads Completion 4 4 0 2.008s
+ Reset Sequences 113 113 0 0.304s
+ Install Comments 0 0 0 0.000s
+ ----------------------------------------------- --------- --------- --------- --------------
+ Total import time 1894 1894 0 12.497s
+ ```
+
+ If there is no output for more than 30 minutes, it's possible `pgloader` encountered an error. See
+ the [troubleshooting guide](#troubleshooting) for more details.
1. Start GitLab:
- ```bash
- sudo gitlab-ctl start
- ```
+ ```bash
+ sudo gitlab-ctl start
+ ```
You can now verify that everything works as expected by visiting GitLab.
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index ab48c9080a9..64ac4f15d5f 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -123,3 +123,17 @@ bottom of the **Provisioning** screen, together with a link to the audit logs.
### Testing Azure connection: invalid credentials
When testing the connection, you may encounter an error: **You appear to have entered invalid credentials. Please confirm you are using the correct information for an administrative account**. If `Tenant URL` and `secret token` are correct, check whether your group path contains characters that may be considered invalid JSON primitives (such as `.`). Removing such characters from the group path typically resolves the error.
+
+### Azure: (Field) can't be blank sync error
+
+When checking the Audit Logs for the Provisioning, you can sometimes see the
+error `Namespace can't be blank, Name can't be blank, and User can't be blank.`
+
+This is likely caused because not all required fields (such as first name and
+last name) are present for all users being mapped.
+
+As a workaround, try an alternate mapping:
+
+1. Follow the Azure mapping instructions from above.
+1. Delete the `name.formatted` target attribute entry.
+1. Change the `displayName` source attribute to have `name.formatted` target attribute.
diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md
index cbee79de493..5b0954195f8 100644
--- a/doc/user/profile/account/delete_account.md
+++ b/doc/user/profile/account/delete_account.md
@@ -1,3 +1,7 @@
+---
+type: howto
+---
+
# Deleting a User account
Users can be deleted from a GitLab instance, either by:
@@ -64,8 +68,20 @@ for such records. Any commits made by a deleted user will still display the
username of the original user.
When a user is deleted from an [abuse report](../../admin_area/abuse_reports.md)
-or spam log, these associated records are not ghosted and will be removed, along
-with any groups the user is a sole owner of.
-
-Administrators can also request this behavior when deleting users from the
-[API](../../../api/users.md#user-deletion) or the Admin Area.
+or spam log, these associated
+records are not ghosted and will be removed, along with any groups the user
+is a sole owner of. Administrators can also request this behavior when
+deleting users from the [API](../../../api/users.md#user-deletion) or the
+Admin Area.
+
+<!-- ## 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/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index d3a634c7b9d..e2b1a20a605 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -1,3 +1,7 @@
+---
+type: howto
+---
+
# Two-Factor Authentication
Two-factor Authentication (2FA) provides an additional level of security to your
@@ -15,7 +19,7 @@ When you enable 2FA, don't forget to back up your [recovery codes](#recovery-cod
In addition to time-based one time passwords (TOTP), GitLab supports U2F
(universal 2nd factor) devices as the second factor of authentication. Once
-enabled, in addition to supplying your username and password to login, you'll
+enabled, in addition to supplying your username and password to log in, you'll
be prompted to activate your U2F device (usually by pressing a button on it),
and it will perform secure authentication on your behalf.
@@ -238,3 +242,15 @@ Sign in and re-enable two-factor authentication as soon as possible.
- The user logs out and attempts to log in via `first.host.xyz` - U2F authentication succeeds.
- The user logs out and attempts to log in via `second.host.xyz` - U2F authentication fails, because
the U2F key has only been registered on `first.host.xyz`.
+
+<!-- ## 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/profile/active_sessions.md b/doc/user/profile/active_sessions.md
index 28e3f4904a9..2d7bd25fc27 100644
--- a/doc/user/profile/active_sessions.md
+++ b/doc/user/profile/active_sessions.md
@@ -1,14 +1,31 @@
+---
+type: howto
+---
+
# Active Sessions
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17867)
> in GitLab 10.8.
GitLab lists all devices that have logged into your account. This allows you to
-review the sessions.
+review the sessions, and revoke any you don't recognize.
## Listing all active sessions
-1. On the upper right corner, click on your avatar and go to your **Settings**.
-1. Navigate to the **Active Sessions** tab.
+1. Click your avatar.
+1. Select **Settings**.
+1. Click **Active Sessions** in the sidebar.
![Active sessions list](img/active_sessions_list.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/profile/index.md b/doc/user/profile/index.md
index fc5eb8c7b56..06710065dfd 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -1,7 +1,12 @@
+---
+type: index, howto
+---
+
# User account
-When signed into their GitLab account, users can customize their
-experience according to the best approach to their cases.
+Each GitLab account has a user profile, and settings. Your [profile](#user-profile)
+contains information about you, and your GitLab activity. Your [settings](#profile-settings)
+allow you to customize some aspects of GitLab to suit yourself.
## Signing in
@@ -10,8 +15,10 @@ See the [authentication topic](../../topics/authentication/index.md) for more de
## User profile
-Your profile is available from the up-right corner menu bar (user's avatar) > **Profile**,
-or from `https://example.gitlab.com/username`.
+To access your profile:
+
+1. Click on your avatar.
+1. Select **Profile**.
On your profile page, you will see the following information:
@@ -24,8 +31,10 @@ On your profile page, you will see the following information:
## Profile settings
-You can edit your account settings by navigating from the up-right corner menu bar
-(user's avatar) > **Settings**, or visiting `https://example.gitlab.com/profile`.
+To access your profile settings:
+
+1. Click on your avatar.
+1. Select **Settings**.
From there, you can:
@@ -56,8 +65,8 @@ before proceeding.
To change your `username`:
1. Navigate to your [profile's](#profile-settings) **Settings > Account**.
-1. Enter a new username under "Change username".
-1. Hit **Update username**.
+1. Enter a new username under **Change username**.
+1. Click **Update username**.
CAUTION: **Caution:**
It is currently not possible to change your username if it contains a
@@ -86,12 +95,15 @@ The following information will be hidden from the user profile page (`https://gi
To enable private profile:
-1. Navigate to your personal [profile settings](#profile-settings).
-1. Check the "Private profile" option.
-1. Hit **Update profile settings**.
+1. Click your avatar.
+1. Select **Profile**.
+1. Click **Edit profile** (pencil icon).
+1. Check the **Private profile** option in the **Main settings** section.
+1. Click **Update profile settings**.
NOTE: **Note:**
-You and GitLab admins can see your the abovementioned information on your profile even if it is private.
+All your profile information can be seen by yourself, and GitLab admins, even if
+the **Private profile** option is enabled.
## Add details of external accounts
@@ -99,9 +111,15 @@ GitLab allows you to add links to certain other external accounts you might have
To add links to other accounts:
-1. Navigate to your **User Settings > Profile**.
-1. In the **Main settings** section, locate and fill out fields for links to external accounts like Skype and Twitter.
-1. Click the **Update profile settings** button.
+1. Click your avatar.
+1. Select **Profile**.
+1. Click **Edit profile** (pencil icon).
+1. Complete the desired fields for external accounts, in the **Main settings**
+ section:
+ - Skype
+ - Twitter
+ - LinkedIn
+1. Click **Update profile settings**.
## Private contributions
@@ -111,9 +129,11 @@ Enabling private contributions will include contributions to private projects, i
To enable private contributions:
-1. Navigate to your personal [profile settings](#profile-settings).
-1. Check the "Private contributions" option.
-1. Hit **Update profile settings**.
+1. Click on your avatar.
+1. Select **Profile**.
+1. Click **Edit profile** (pencil icon).
+1. Check the **Private contributions** option.
+1. Click **Update profile settings**.
## Current status
@@ -124,22 +144,24 @@ This may be helpful when you are out of office or otherwise not available.
Other users can then take your status into consideration when responding to your issues or assigning work to you.
Please be aware that your status is publicly visible even if your [profile is private](#private-profile).
+Status messages are restricted to 100 characters of plain text.
+They may however contain emoji codes such as `I'm on vacation :palm_tree:`.
+
To set your current status:
-1. Open the user menu in the top-right corner of the navigation bar.
-1. Hit **Set status**, or **Edit status** if you have already set a status.
-1. Set the emoji and/or status message to your liking.
-1. Hit **Set status**. Alternatively, you can also hit **Remove status** to remove your user status entirely.
+1. Click your avatar.
+1. Click **Set status**, or **Edit status** if you have already set a status.
+1. Set the desired emoji and/or status message.
+1. Click **Set status**. Alternatively, you can click **Remove status** to remove your user status entirely.
or
-1. Navigate to your personal [profile settings](#profile-settings).
-1. In the text field below `Your status`, enter your status message.
-1. Select an emoji from the dropdown if you like.
-1. Hit **Update profile settings**.
-
-Status messages are restricted to 100 characters of plain text.
-They may however contain emoji codes such as `I'm on vacation :palm_tree:`.
+1. Click your avatar.
+1. Select **Profile**.
+1. Click **Edit profile** (pencil icon).
+1. Enter your status message in the **Your status** text field.
+1. Click **Add status emoji** (smiley face), and select the desired emoji.
+1. Click **Update profile settings**.
You can also set your current status [using the API](../../api/users.md#user-status).
@@ -153,34 +175,36 @@ Any of your own verified email addresses can be used as the commit email.
To change your commit email:
-1. Click on your avatar at the top-right corner of the navigation bar.
-1. From the menu that appears, click **Settings**.
-1. In the **Main settings** section, locate **Commit email** dropdown.
+1. Click your avatar.
+1. Select **Profile**.
+1. Click **Edit profile** (pencil icon).
+1. Click **Commit email** dropdown.
1. Select any of the verified emails.
-1. Press **Update profile settings**.
+1. Click **Update profile settings**.
### Private commit email
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22560) in GitLab 11.5.
-GitLab provides users with an automatically generated private commit email option,
-which allows the user to not make their email information public.
+GitLab provides the user with an automatically generated private commit email option,
+which allows the user to keep their email information private.
To enable this option:
-1. Click on your avatar at the top-right corner of the navigation bar.
-1. From the menu that appears, click **Settings**.
-1. In the **Main settings** section, locate **Commit email** dropdown.
-1. Select the "Use a private email" option.
-1. Press **Update profile settings**.
+1. Click your avatar.
+1. Select **Profile**.
+1. Click **Edit profile** (pencil icon).
+1. Click **Commit email** dropdown.
+1. Select **Use a private email** option.
+1. Click **Update profile settings**.
Once this option is enabled, every Git-related action will be performed using the private commit email.
-In order to stay fully anonymous, you can also copy this private commit email
+To stay fully anonymous, you can also copy this private commit email
and configure it on your local machine using the following command:
```sh
-git config --global user.email <YOUR_PRIVATE_COMMIT_EMAIL>
+git config --global user.email <your email address>
```
## Troubleshooting
@@ -203,3 +227,15 @@ to get you a new `_gitlab_session` and keep you signed in through browser restar
After your `remember_user_token` expires and your `_gitlab_session` is cleared/expired,
you will be asked to sign in again to verify your identity (which is for security reasons).
+
+<!-- ## 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/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md
index 0b224fc7e01..248188a6457 100644
--- a/doc/user/profile/personal_access_tokens.md
+++ b/doc/user/profile/personal_access_tokens.md
@@ -1,3 +1,7 @@
+---
+type: concepts, howto
+---
+
# Personal access tokens
> [Introduced][ce-3749] in GitLab 8.8.
@@ -52,3 +56,15 @@ the following table.
[container registry]: ../project/container_registry.md
[users]: ../../api/users.md
[usage]: ../../api/README.md#personal-access-tokens
+
+<!-- ## 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/profile/preferences.md b/doc/user/profile/preferences.md
index b1fde3b577b..5bd4b263a58 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -1,11 +1,17 @@
+---
+type: concepts, howto
+---
+
# Profile preferences
A user's profile preferences page allows the user to customize various aspects
of GitLab to their liking.
-To navigate to your profile's preferences, click your avatar icon in the top
-right corner, select **Settings** and then choose **Preferences** from the
-left sidebar.
+To navigate to your profile's preferences:
+
+1. Click your avatar.
+1. Select **Settings**.
+1. Click **Preferences** in the sidebar.
## Navigation theme
@@ -15,7 +21,7 @@ and left side navigation.
Using individual color themes might help you differentiate between your different
GitLab instances.
-The default palette is Indigo. You can choose between 10 different themes:
+The default theme is Indigo. You can choose between 10 themes:
- Indigo
- Light Indigo
@@ -39,7 +45,7 @@ for syntax highlighting. For a list of supported languages visit the rouge websi
Changing this setting allows you to customize the color theme when viewing any
syntax highlighted code on GitLab.
-The default syntax theme is White, and you can choose among 5 different colors:
+The default syntax theme is White, and you can choose among 5 different themes:
- White
- Dark
@@ -102,7 +108,7 @@ Select your preferred language from a list of supported languages.
### First day of the week
-The first day of the week can be customised for calendar views and date pickers.
+The first day of the week can be customized for calendar views and date pickers.
You can choose one of the following options as the first day of the week:
@@ -111,3 +117,15 @@ You can choose one of the following options as the first day of the week:
- Monday
If you select **System Default**, the system-wide default setting will be used.
+
+<!-- ## 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/project/clusters/index.md b/doc/user/project/clusters/index.md
index 918944d72a1..f0d80dad94f 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -620,8 +620,16 @@ use an A record. If your external endpoint is a hostname, use a CNAME record.
## Deploying to a Kubernetes cluster
-A Kubernetes cluster can be the destination for a deployment job using special
-[deployment variables](#deployment-variables).
+A Kubernetes cluster can be the destination for a deployment job. If
+
+- The cluster is integrated with GitLab, special
+ [deployment variables](#deployment-variables) are made available to your job
+ and configuration is not required. You can immediately begin interacting with
+ the cluster from your jobs using tools such as `kubectl` or `helm`.
+- You don't use GitLab's cluster integration you can still deploy to your
+ cluster. However, you will need configure Kubernetes tools yourself
+ using [environment variables](../../../ci/variables/README.md#creating-a-custom-environment-variable)
+ before you can interact with the cluster from your jobs.
### Deployment variables
diff --git a/doc/user/project/issues/csv_export.md b/doc/user/project/issues/csv_export.md
index d3f53c09fb3..27ce3a814f9 100644
--- a/doc/user/project/issues/csv_export.md
+++ b/doc/user/project/issues/csv_export.md
@@ -72,4 +72,4 @@ Data will be encoded with a comma as the column delimiter, with `"` used to quot
## Limitations
-As the issues will be sent as an email attachment, there is a limit on how much data can be exported. Currently this limit is 20MB to ensure successful delivery across a range of email providers. If this limit is reached we suggest narrowing the search before export, perhaps by exporting open and closed issues separately.
+As the issues will be sent as an email attachment, there is a limit on how much data can be exported. Currently this limit is 15MB to ensure successful delivery across a range of email providers. If this limit is reached we suggest narrowing the search before export, perhaps by exporting open and closed issues separately.
diff --git a/doc/workflow/git_annex.md b/doc/workflow/git_annex.md
index 84d25951908..9543859f86f 100644
--- a/doc/workflow/git_annex.md
+++ b/doc/workflow/git_annex.md
@@ -54,13 +54,13 @@ sudo yum install epel-release && sudo yum install git-annex
For omnibus-gitlab packages, only one configuration setting is needed.
The Omnibus package will internally set the correct options in all locations.
-1. In `/etc/gitlab/gitlab.rb` add the following line:
+1. In `/etc/gitlab/gitlab.rb` add the following line:
- ```ruby
- gitlab_shell['git_annex_enabled'] = true
- ```
+ ```ruby
+ gitlab_shell['git_annex_enabled'] = true
+ ```
-1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
### Configuration for installations from source
@@ -69,20 +69,20 @@ There are 2 settings to enable git-annex on your GitLab server.
One is located in `config/gitlab.yml` of the GitLab repository and the other
one is located in `config.yml` of gitlab-shell.
-1. In `config/gitlab.yml` add or edit the following lines:
+1. In `config/gitlab.yml` add or edit the following lines:
- ```yaml
- gitlab_shell:
- git_annex_enabled: true
- ```
+ ```yaml
+ gitlab_shell:
+ git_annex_enabled: true
+ ```
-1. In `config.yml` of gitlab-shell add or edit the following lines:
+1. In `config.yml` of gitlab-shell add or edit the following lines:
- ```yaml
- git_annex_enabled: true
- ```
+ ```yaml
+ git_annex_enabled: true
+ ```
-1. Save the files and [restart GitLab][] for the changes to take effect.
+1. Save the files and [restart GitLab][] for the changes to take effect.
## Using GitLab git-annex
diff --git a/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md b/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md
index 71c73e3dffe..75673d23799 100644
--- a/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md
+++ b/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md
@@ -46,25 +46,24 @@ need to do (we assume you have [git-annex enabled](../git_annex.md#using-gitlab-
repository and that you have made backups in case something goes wrong).
Fire up a terminal, navigate to your Git repository and:
-
1. Disable `git-annex`:
- ```bash
- git annex sync --content
- git annex direct
- git annex uninit
- git annex indirect
- ```
+ ```bash
+ git annex sync --content
+ git annex direct
+ git annex uninit
+ git annex indirect
+ ```
1. Enable `git-lfs`:
- ```
- git lfs install
- git lfs track <files>
- git add .
- git commit -m "commit message"
- git push
- ```
+ ```
+ git lfs install
+ git lfs track <files>
+ git add .
+ git commit -m "commit message"
+ git push
+ ```
### Disabling Git Annex in your repo
@@ -86,72 +85,72 @@ if the server also has Git Annex 6 installed. Read more in the
1. Backup your repository
- ```bash
- cd repository
- git annex sync --content
- cd ..
- git clone repository repository-backup
- cd repository-backup
- git annex get
- cd ..
- ```
+ ```bash
+ cd repository
+ git annex sync --content
+ cd ..
+ git clone repository repository-backup
+ cd repository-backup
+ git annex get
+ cd ..
+ ```
1. Use `annex direct`:
- ```bash
- cd repository
- git annex direct
- ```
+ ```bash
+ cd repository
+ git annex direct
+ ```
- The output should be similar to this:
+ The output should be similar to this:
- ```bash
- commit
- On branch master
- Your branch is up-to-date with 'origin/master'.
- nothing to commit, working tree clean
- ok
- direct debian.iso ok
- direct ok
- ```
+ ```bash
+ commit
+ On branch master
+ Your branch is up-to-date with 'origin/master'.
+ nothing to commit, working tree clean
+ ok
+ direct debian.iso ok
+ direct ok
+ ```
1. Disable Git Annex with [`annex uninit`][uninit]:
- ```bash
- git annex uninit
- ```
+ ```bash
+ git annex uninit
+ ```
- The output should be similar to this:
+ The output should be similar to this:
- ```bash
- unannex debian.iso ok
- Deleted branch git-annex (was 2534d2c).
- ```
+ ```bash
+ unannex debian.iso ok
+ Deleted branch git-annex (was 2534d2c).
+ ```
- This will `unannex` every file in the repository, leaving the original files.
+ This will `unannex` every file in the repository, leaving the original files.
1. Switch back to `indirect` mode:
- ```bash
- git annex indirect
- ```
-
- The output should be similar to this:
+ ```bash
+ git annex indirect
+ ```
- ```bash
- (merging origin/git-annex into git-annex...)
- (recording state in git...)
- commit (recording state in git...)
+ The output should be similar to this:
- ok
- (recording state in git...)
- [master fac3194] commit before switching to indirect mode
- 1 file changed, 1 deletion(-)
- delete mode 120000 alpine-virt-3.4.4-x86_64.iso
- ok
- indirect ok
- ok
- ```
+ ```bash
+ (merging origin/git-annex into git-annex...)
+ (recording state in git...)
+ commit (recording state in git...)
+
+ ok
+ (recording state in git...)
+ [master fac3194] commit before switching to indirect mode
+ 1 file changed, 1 deletion(-)
+ delete mode 120000 alpine-virt-3.4.4-x86_64.iso
+ ok
+ indirect ok
+ ok
+ ```
---
@@ -216,16 +215,16 @@ branches created by Git Annex: `git-annex`, and all under `synced/`.
![repository branches](images/git-annex-branches.png)
-You can also do this on the commandline with:
+You can also do this on the command line with:
- ```bash
- git branch -d synced/master
- git branch -d synced/git-annex
- git push origin :synced/master
- git push origin :synced/git-annex
- git push origin :git-annex
- git remote prune origin
- ```
+```bash
+git branch -d synced/master
+git branch -d synced/git-annex
+git push origin :synced/master
+git push origin :synced/git-annex
+git push origin :git-annex
+git remote prune origin
+```
If there are still some Annex objects inside your repository (`.git/annex/`)
or references inside `.git/config`, run `annex uninit` again:
diff --git a/doc/workflow/time_tracking.md b/doc/workflow/time_tracking.md
index b55c6b2e3df..fad853f8a44 100644
--- a/doc/workflow/time_tracking.md
+++ b/doc/workflow/time_tracking.md
@@ -22,8 +22,8 @@ below.
## How to enter data
-Time Tracking uses two [quick actions] that GitLab introduced with this new
-feature: `/spend` and `/estimate`.
+Time Tracking uses two [quick actions](../user/project/quick_actions.md)
+that GitLab introduced with this new feature: `/spend` and `/estimate`.
Quick actions can be used in the body of an issue or a merge request, but also
in a comment in both an issue or a merge request.
@@ -73,16 +73,15 @@ The following time units are available:
Default conversion rates are 1mo = 4w, 1w = 5d and 1d = 8h.
-### Limit displayed units to hours
+### Limit displayed units to hours **(CORE ONLY)**
-> Introduced in GitLab 12.1.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29469/) in GitLab 12.1.
-The display of time units can be limited to hours through the option in **Admin Area > Settings > Preferences** under 'Localization'.
+In GitLab self-managed instances, the display of time units can be limited to
+hours through the option in **Admin Area > Settings > Preferences** under **Localization**.
With this option enabled, `75h` is displayed instead of `1w 4d 3h`.
## Other interesting links
- [Time Tracking landing page on about.gitlab.com](https://about.gitlab.com/solutions/time-tracking/)
-
-[quick actions]: ../user/project/quick_actions.md
diff --git a/doc/workflow/workflow.md b/doc/workflow/workflow.md
index f70e41df842..7fac41c3b6f 100644
--- a/doc/workflow/workflow.md
+++ b/doc/workflow/workflow.md
@@ -1,31 +1,31 @@
# Feature branch workflow
-1. Clone project:
+1. Clone project:
- ```bash
- git clone git@example.com:project-name.git
- ```
+ ```bash
+ git clone git@example.com:project-name.git
+ ```
-1. Create branch with your feature:
+1. Create branch with your feature:
- ```bash
- git checkout -b $feature_name
- ```
+ ```bash
+ git checkout -b $feature_name
+ ```
-1. Write code. Commit changes:
+1. Write code. Commit changes:
- ```bash
- git commit -am "My feature is ready"
- ```
+ ```bash
+ git commit -am "My feature is ready"
+ ```
-1. Push your branch to GitLab:
+1. Push your branch to GitLab:
- ```bash
- git push origin $feature_name
- ```
+ ```bash
+ git push origin $feature_name
+ ```
-1. Review your code on commits page.
+1. Review your code on commits page.
-1. Create a merge request.
+1. Create a merge request.
-1. Your team lead will review the code &amp; merge it to the main branch.
+1. Your team lead will review the code &amp; merge it to the main branch.
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 4275d911708..aa9e879160d 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -59,7 +59,7 @@ module API
optional :grafana_url, type: String, desc: 'Grafana URL'
optional :gravatar_enabled, type: Boolean, desc: 'Flag indicating if the Gravatar service is enabled'
optional :help_page_hide_commercial_content, type: Boolean, desc: 'Hide marketing-related entries from help'
- optional :help_page_support_url, type: String, desc: 'Alternate support URL for help page'
+ optional :help_page_support_url, type: String, desc: 'Alternate support URL for help page and help dropdown'
optional :help_page_text, type: String, desc: 'Custom text displayed on the help page'
optional :home_page_url, type: String, desc: 'We will redirect non-logged in users to this page'
optional :housekeeping_enabled, type: Boolean, desc: 'Enable automatic repository housekeeping (git repack, git gc)'
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index c98de722fe1..4783832961d 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -413,7 +413,7 @@ module Gitlab
metadata_file = File.read(storage_metadata_file_path(storage))
metadata_hash = JSON.parse(metadata_file)
metadata_hash['gitaly_filesystem_id']
- rescue Errno::ENOENT, Errno::ACCESS, JSON::ParserError
+ rescue Errno::ENOENT, Errno::EACCES, JSON::ParserError
nil
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 591dc2a7e39..878ee5bc344 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -966,7 +966,7 @@ msgstr ""
msgid "Allows you to add and manage Kubernetes clusters."
msgstr ""
-msgid "Alternate support URL for help page"
+msgid "Alternate support URL for help page and help dropdown"
msgstr ""
msgid "Alternatively, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import."
@@ -9238,7 +9238,7 @@ msgstr ""
msgid "Requests Profiles"
msgstr ""
-msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are disabled. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The whitelist can hold a maximum of 4000 entries. Domains should use IDNA encoding. Ex: domain.com, 192.168.1.1, 127.0.0.0/28."
+msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The whitelist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
msgid "Require all users in this group to setup Two-factor authentication"
@@ -10586,6 +10586,9 @@ msgstr ""
msgid "Sunday"
msgstr ""
+msgid "Support"
+msgstr ""
+
msgid "Support for custom certificates is disabled. Ask your system's administrator to enable it."
msgstr ""
@@ -13134,10 +13137,10 @@ msgstr ""
msgid "encrypted: needs to be a :required, :optional or :migrating!"
msgstr ""
-msgid "entries cannot be blank"
+msgid "entries cannot be larger than 255 characters"
msgstr ""
-msgid "entries cannot be larger than 255 characters"
+msgid "entries cannot be nil"
msgstr ""
msgid "entries cannot contain HTML tags"
diff --git a/package.json b/package.json
index dfa8e8fe4d7..c97046b0e84 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"@babel/preset-env": "^7.4.4",
"@gitlab/csslab": "^1.9.0",
"@gitlab/svgs": "^1.67.0",
- "@gitlab/ui": "^5.9.0",
+ "@gitlab/ui": "^5.11.1",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
"apollo-link": "^1.2.11",
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index e78b9bece19..4e5610d69b7 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -181,6 +181,10 @@ module QA
ENV.fetch('GCLOUD_REGION')
end
+ def gcloud_num_nodes
+ ENV.fetch('GCLOUD_NUM_NODES', 3)
+ end
+
def has_gcloud_credentials?
%w[GCLOUD_ACCOUNT_KEY GCLOUD_ACCOUNT_EMAIL].none? { |var| ENV[var].to_s.empty? }
end
diff --git a/qa/qa/service/kubernetes_cluster.rb b/qa/qa/service/kubernetes_cluster.rb
index 40263e94065..ac0b6313167 100644
--- a/qa/qa/service/kubernetes_cluster.rb
+++ b/qa/qa/service/kubernetes_cluster.rb
@@ -29,6 +29,8 @@ module QA
#{auth_options}
--enable-basic-auth
--region #{Runtime::Env.gcloud_region}
+ --disk-size 10GB
+ --num-nodes #{Runtime::Env.gcloud_num_nodes}
&& gcloud container clusters
get-credentials
--region #{Runtime::Env.gcloud_region}
diff --git a/rubocop/cop/inject_enterprise_edition_module.rb b/rubocop/cop/inject_enterprise_edition_module.rb
index 1d37b1bd12d..e0e1b2d6c7d 100644
--- a/rubocop/cop/inject_enterprise_edition_module.rb
+++ b/rubocop/cop/inject_enterprise_edition_module.rb
@@ -6,23 +6,39 @@ module RuboCop
# the last line of a file. Injecting a module in the middle of a file will
# cause merge conflicts, while placing it on the last line will not.
class InjectEnterpriseEditionModule < RuboCop::Cop::Cop
- MSG = 'Injecting EE modules must be done on the last line of this file' \
- ', outside of any class or module definitions'
+ INVALID_LINE = 'Injecting EE modules must be done on the last line of this file' \
+ ', outside of any class or module definitions'
- METHODS = Set.new(%i[include extend prepend]).freeze
+ DISALLOWED_METHOD =
+ 'EE modules must be injected using `include_if_ee`, `extend_if_ee`, or `prepend_if_ee`'
+
+ INVALID_ARGUMENT = 'EE modules to inject must be specified as a String'
+
+ CHECK_LINE_METHODS =
+ Set.new(%i[include_if_ee extend_if_ee prepend_if_ee]).freeze
+
+ DISALLOW_METHODS = Set.new(%i[include extend prepend]).freeze
def ee_const?(node)
line = node.location.expression.source_line
# We use `match?` here instead of RuboCop's AST matching, as this makes
# it far easier to handle nested constants such as `EE::Foo::Bar::Baz`.
- line.match?(/(\s|\()(::)?EE::/)
+ line.match?(/(\s|\()('|")?(::)?EE::/)
end
def on_send(node)
- return unless METHODS.include?(node.children[1])
- return unless ee_const?(node.children[2])
+ return unless check_method?(node)
+ if DISALLOW_METHODS.include?(node.children[1])
+ add_offense(node, message: DISALLOWED_METHOD)
+ else
+ verify_line_number(node)
+ verify_argument_type(node)
+ end
+ end
+
+ def verify_line_number(node)
line = node.location.line
buffer = node.location.expression.source_buffer
last_line = buffer.last_line
@@ -32,7 +48,25 @@ module RuboCop
# the expression is the last line _of code_.
last_line -= 1 if buffer.source.end_with?("\n")
- add_offense(node) if line < last_line
+ add_offense(node, message: INVALID_LINE) if line < last_line
+ end
+
+ def verify_argument_type(node)
+ argument = node.children[2]
+
+ return if argument.str_type?
+
+ add_offense(argument, message: INVALID_ARGUMENT)
+ end
+
+ def check_method?(node)
+ name = node.children[1]
+
+ if CHECK_LINE_METHODS.include?(name) || DISALLOW_METHODS.include?(name)
+ ee_const?(node.children[2])
+ else
+ false
+ end
end
# Automatically correcting these offenses is not always possible, as
diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb
index 91ef7653822..f5a487b4d57 100644
--- a/spec/fast_spec_helper.rb
+++ b/spec/fast_spec_helper.rb
@@ -4,6 +4,7 @@ ENV['GITLAB_ENV'] = 'test'
ENV['IN_MEMORY_APPLICATION_SETTINGS'] = 'true'
require 'active_support/dependencies'
+require_relative '../config/initializers/0_inject_enterprise_edition_module'
require_relative '../config/settings'
require_relative 'support/rspec'
require 'active_support/all'
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index a074bbcff0a..c77605f3869 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -356,16 +356,18 @@ describe 'Admin updates settings' do
end
it 'Change Help page' do
+ new_support_url = 'http://example.com/help'
+
page.within('.as-help-page') do
fill_in 'Help page text', with: 'Example text'
check 'Hide marketing-related entries from help'
- fill_in 'Support page URL', with: 'http://example.com/help'
+ fill_in 'Support page URL', with: new_support_url
click_button 'Save changes'
end
expect(current_settings.help_page_text).to eq "Example text"
expect(current_settings.help_page_hide_commercial_content).to be_truthy
- expect(current_settings.help_page_support_url).to eq "http://example.com/help"
+ expect(current_settings.help_page_support_url).to eq new_support_url
expect(page).to have_content "Application settings saved successfully"
end
@@ -415,6 +417,34 @@ describe 'Admin updates settings' do
end
end
+ context 'Nav bar' do
+ it 'Shows default help links in nav' do
+ default_support_url = 'https://about.gitlab.com/getting-help/'
+
+ visit root_dashboard_path
+
+ find('.header-help-dropdown-toggle').click
+
+ page.within '.header-help' do
+ expect(page).to have_link(text: 'Help', href: help_path)
+ expect(page).to have_link(text: 'Support', href: default_support_url)
+ end
+ end
+
+ it 'Shows custom support url in nav when set' do
+ new_support_url = 'http://example.com/help'
+ stub_application_setting(help_page_support_url: new_support_url)
+
+ visit root_dashboard_path
+
+ find('.header-help-dropdown-toggle').click
+
+ page.within '.header-help' do
+ expect(page).to have_link(text: 'Support', href: new_support_url)
+ end
+ end
+ end
+
def check_all_events
page.check('Active')
page.check('Push')
diff --git a/spec/javascripts/boards/components/boards_selector_spec.js b/spec/javascripts/boards/components/boards_selector_spec.js
index 504bc51778c..473cc0612ea 100644
--- a/spec/javascripts/boards/components/boards_selector_spec.js
+++ b/spec/javascripts/boards/components/boards_selector_spec.js
@@ -76,7 +76,8 @@ describe('BoardsSelector', () => {
document.querySelector('.js-boards-selector'),
);
- vm.$el.querySelector('.js-dropdown-toggle').click();
+ // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
+ vm.$children[0].$emit('show');
Promise.all([allBoardsResponse, recentBoardsResponse])
.then(() => vm.$nextTick())
diff --git a/spec/javascripts/pdf/page_spec.js b/spec/javascripts/pdf/page_spec.js
index 6dea570266b..efeb65acf87 100644
--- a/spec/javascripts/pdf/page_spec.js
+++ b/spec/javascripts/pdf/page_spec.js
@@ -17,7 +17,7 @@ describe('Page component', () => {
pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
pdfjsLib
.getDocument(testPDF)
- .then(pdf => pdf.getPage(1))
+ .promise.then(pdf => pdf.getPage(1))
.then(page => {
testPage = page;
})
@@ -31,7 +31,8 @@ describe('Page component', () => {
it('renders the page when mounting', done => {
const promise = Promise.resolve();
- spyOn(testPage, 'render').and.callFake(() => promise);
+ spyOn(testPage, 'render').and.returnValue({ promise });
+
vm = mountComponent(Component, {
page: testPage,
number: 1,
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index e1d24ae8977..e9fb6c0125c 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -17,6 +17,16 @@ describe Gitlab::GitalyClient do
})
end
+ describe '.filesystem_id_from_disk' do
+ it 'catches errors' do
+ [Errno::ENOENT, Errno::EACCES, JSON::ParserError].each do |error|
+ allow(File).to receive(:read).with(described_class.storage_metadata_file_path('default')).and_raise(error)
+
+ expect(described_class.filesystem_id_from_disk('default')).to be_nil
+ end
+ end
+ end
+
describe '.stub_class' do
it 'returns the gRPC health check stub' do
expect(described_class.stub_class(:health_check)).to eq(::Grpc::Health::V1::Health::Stub)
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index bd87bbd8d68..db80b85360f 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -45,7 +45,7 @@ describe ApplicationSetting do
it { is_expected.to allow_value(['xn--itlab-j1a.com']).for(:outbound_local_requests_whitelist) }
it { is_expected.not_to allow_value(['<h1></h1>']).for(:outbound_local_requests_whitelist) }
it { is_expected.to allow_value(['gitlab.com']).for(:outbound_local_requests_whitelist) }
- it { is_expected.to allow_value(nil).for(:outbound_local_requests_whitelist) }
+ it { is_expected.not_to allow_value(nil).for(:outbound_local_requests_whitelist) }
it { is_expected.to allow_value([]).for(:outbound_local_requests_whitelist) }
context "when user accepted let's encrypt terms of service" do
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 8f2f1b200e4..761695bfe91 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -121,26 +121,6 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
end
end
- describe '.missing_kubernetes_namespace' do
- let!(:cluster) { create(:cluster, :provided_by_gcp, :project) }
- let(:project) { cluster.project }
- let(:kubernetes_namespaces) { project.kubernetes_namespaces }
-
- subject do
- described_class.joins(:projects).where(projects: { id: project.id }).missing_kubernetes_namespace(kubernetes_namespaces)
- end
-
- it { is_expected.to contain_exactly(cluster) }
-
- context 'kubernetes namespace exists' do
- before do
- create(:cluster_kubernetes_namespace, project: project, cluster: cluster)
- end
-
- it { is_expected.to be_empty }
- end
- end
-
describe 'validations' do
subject { cluster.valid? }
@@ -423,31 +403,6 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
end
end
- describe '#all_projects' do
- let(:project) { create(:project) }
- let(:cluster) { create(:cluster, projects: [project]) }
-
- subject { cluster.all_projects }
-
- context 'project cluster' do
- it 'returns project' do
- is_expected.to eq([project])
- end
- end
-
- context 'group cluster' do
- let(:cluster) { create(:cluster, :group) }
- let(:group) { cluster.group }
- let(:project) { create(:project, group: group) }
- let(:subgroup) { create(:group, parent: group) }
- let(:subproject) { create(:project, group: subgroup) }
-
- it 'returns all projects for group' do
- is_expected.to contain_exactly(project, subproject)
- end
- end
- end
-
describe '#first_project' do
subject { cluster.first_project }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 24dfd0c5605..32fb0c0ff73 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -173,24 +173,6 @@ describe Project do
it { is_expected.to include_module(Sortable) }
end
- describe '.missing_kubernetes_namespace' do
- let!(:project) { create(:project) }
- let!(:cluster) { create(:cluster, :provided_by_user, :group) }
- let(:kubernetes_namespaces) { project.kubernetes_namespaces }
-
- subject { described_class.missing_kubernetes_namespace(kubernetes_namespaces) }
-
- it { is_expected.to contain_exactly(project) }
-
- context 'kubernetes namespace exists' do
- before do
- create(:cluster_kubernetes_namespace, project: project, cluster: cluster)
- end
-
- it { is_expected.to be_empty }
- end
- end
-
describe 'validation' do
let!(:project) { create(:project) }
diff --git a/spec/rubocop/cop/inject_enterprise_edition_module_spec.rb b/spec/rubocop/cop/inject_enterprise_edition_module_spec.rb
index 0ff777388e5..27df42c0aee 100644
--- a/spec/rubocop/cop/inject_enterprise_edition_module_spec.rb
+++ b/spec/rubocop/cop/inject_enterprise_edition_module_spec.rb
@@ -10,91 +10,91 @@ describe RuboCop::Cop::InjectEnterpriseEditionModule do
subject(:cop) { described_class.new }
- it 'flags the use of `prepend EE` in the middle of a file' do
+ it 'flags the use of `prepend_if_ee EE` in the middle of a file' do
expect_offense(<<~SOURCE)
class Foo
- prepend EE::Foo
- ^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ prepend_if_ee 'EE::Foo'
+ ^^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
end
SOURCE
end
- it 'does not flag the use of `prepend EEFoo` in the middle of a file' do
+ it 'does not flag the use of `prepend_if_ee EEFoo` in the middle of a file' do
expect_no_offenses(<<~SOURCE)
class Foo
- prepend EEFoo
+ prepend_if_ee 'EEFoo'
end
SOURCE
end
- it 'flags the use of `prepend EE::Foo::Bar` in the middle of a file' do
+ it 'flags the use of `prepend_if_ee EE::Foo::Bar` in the middle of a file' do
expect_offense(<<~SOURCE)
class Foo
- prepend EE::Foo::Bar
- ^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ prepend_if_ee 'EE::Foo::Bar'
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
end
SOURCE
end
- it 'flags the use of `prepend(EE::Foo::Bar)` in the middle of a file' do
+ it 'flags the use of `prepend_if_ee(EE::Foo::Bar)` in the middle of a file' do
expect_offense(<<~SOURCE)
class Foo
- prepend(EE::Foo::Bar)
- ^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ prepend_if_ee('EE::Foo::Bar')
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
end
SOURCE
end
- it 'flags the use of `prepend EE::Foo::Bar::Baz` in the middle of a file' do
+ it 'flags the use of `prepend_if_ee EE::Foo::Bar::Baz` in the middle of a file' do
expect_offense(<<~SOURCE)
class Foo
- prepend EE::Foo::Bar::Baz
- ^^^^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ prepend_if_ee 'EE::Foo::Bar::Baz'
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
end
SOURCE
end
- it 'flags the use of `prepend ::EE` in the middle of a file' do
+ it 'flags the use of `prepend_if_ee ::EE` in the middle of a file' do
expect_offense(<<~SOURCE)
class Foo
- prepend ::EE::Foo
- ^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ prepend_if_ee '::EE::Foo'
+ ^^^^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
end
SOURCE
end
- it 'flags the use of `include EE` in the middle of a file' do
+ it 'flags the use of `include_if_ee EE` in the middle of a file' do
expect_offense(<<~SOURCE)
class Foo
- include EE::Foo
- ^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ include_if_ee 'EE::Foo'
+ ^^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
end
SOURCE
end
- it 'flags the use of `include ::EE` in the middle of a file' do
+ it 'flags the use of `include_if_ee ::EE` in the middle of a file' do
expect_offense(<<~SOURCE)
class Foo
- include ::EE::Foo
- ^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ include_if_ee '::EE::Foo'
+ ^^^^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
end
SOURCE
end
- it 'flags the use of `extend EE` in the middle of a file' do
+ it 'flags the use of `extend_if_ee EE` in the middle of a file' do
expect_offense(<<~SOURCE)
class Foo
- extend EE::Foo
- ^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ extend_if_ee 'EE::Foo'
+ ^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
end
SOURCE
end
- it 'flags the use of `extend ::EE` in the middle of a file' do
+ it 'flags the use of `extend_if_ee ::EE` in the middle of a file' do
expect_offense(<<~SOURCE)
class Foo
- extend ::EE::Foo
- ^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
+ extend_if_ee '::EE::Foo'
+ ^^^^^^^^^^^^^^^^^^^^^^^^ Injecting EE modules must be done on the last line of this file, outside of any class or module definitions
end
SOURCE
end
@@ -102,7 +102,7 @@ describe RuboCop::Cop::InjectEnterpriseEditionModule do
it 'does not flag prepending of regular modules' do
expect_no_offenses(<<~SOURCE)
class Foo
- prepend Foo
+ prepend_if_ee 'Foo'
end
SOURCE
end
@@ -110,7 +110,7 @@ describe RuboCop::Cop::InjectEnterpriseEditionModule do
it 'does not flag including of regular modules' do
expect_no_offenses(<<~SOURCE)
class Foo
- include Foo
+ include_if_ee 'Foo'
end
SOURCE
end
@@ -118,51 +118,111 @@ describe RuboCop::Cop::InjectEnterpriseEditionModule do
it 'does not flag extending using regular modules' do
expect_no_offenses(<<~SOURCE)
class Foo
- extend Foo
+ extend_if_ee 'Foo'
end
SOURCE
end
- it 'does not flag the use of `prepend EE` on the last line' do
+ it 'does not flag the use of `prepend_if_ee EE` on the last line' do
expect_no_offenses(<<~SOURCE)
class Foo
end
- Foo.prepend(EE::Foo)
+ Foo.prepend_if_ee('EE::Foo')
SOURCE
end
- it 'does not flag the use of `include EE` on the last line' do
+ it 'does not flag the use of `include_if_ee EE` on the last line' do
expect_no_offenses(<<~SOURCE)
class Foo
end
- Foo.include(EE::Foo)
+ Foo.include_if_ee('EE::Foo')
SOURCE
end
- it 'does not flag the use of `extend EE` on the last line' do
+ it 'does not flag the use of `extend_if_ee EE` on the last line' do
expect_no_offenses(<<~SOURCE)
class Foo
end
- Foo.extend(EE::Foo)
+ Foo.extend_if_ee('EE::Foo')
SOURCE
end
it 'autocorrects offenses by just disabling the Cop' do
source = <<~SOURCE
class Foo
- prepend EE::Foo
- include Bar
+ prepend_if_ee 'EE::Foo'
+ include_if_ee 'Bar'
end
SOURCE
expect(autocorrect_source(source)).to eq(<<~SOURCE)
class Foo
- prepend EE::Foo # rubocop: disable Cop/InjectEnterpriseEditionModule
- include Bar
+ prepend_if_ee 'EE::Foo' # rubocop: disable Cop/InjectEnterpriseEditionModule
+ include_if_ee 'Bar'
+ end
+ SOURCE
+ end
+
+ it 'disallows the use of prepend to inject an EE module' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ end
+
+ Foo.prepend(EE::Foo)
+ ^^^^^^^^^^^^^^^^^^^^ EE modules must be injected using `include_if_ee`, `extend_if_ee`, or `prepend_if_ee`
+ SOURCE
+ end
+
+ it 'disallows the use of extend to inject an EE module' do
+ expect_offense(<<~SOURCE)
+ class Foo
end
+
+ Foo.extend(EE::Foo)
+ ^^^^^^^^^^^^^^^^^^^ EE modules must be injected using `include_if_ee`, `extend_if_ee`, or `prepend_if_ee`
+ SOURCE
+ end
+
+ it 'disallows the use of include to inject an EE module' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ end
+
+ Foo.include(EE::Foo)
+ ^^^^^^^^^^^^^^^^^^^^ EE modules must be injected using `include_if_ee`, `extend_if_ee`, or `prepend_if_ee`
+ SOURCE
+ end
+
+ it 'disallows the use of prepend_if_ee without a String' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ end
+
+ Foo.prepend_if_ee(EE::Foo)
+ ^^^^^^^ EE modules to inject must be specified as a String
+ SOURCE
+ end
+
+ it 'disallows the use of include_if_ee without a String' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ end
+
+ Foo.include_if_ee(EE::Foo)
+ ^^^^^^^ EE modules to inject must be specified as a String
+ SOURCE
+ end
+
+ it 'disallows the use of extend_if_ee without a String' do
+ expect_offense(<<~SOURCE)
+ class Foo
+ end
+
+ Foo.extend_if_ee(EE::Foo)
+ ^^^^^^^ EE modules to inject must be specified as a String
SOURCE
end
end
diff --git a/spec/services/metrics/dashboard/default_embed_service_spec.rb b/spec/services/metrics/dashboard/default_embed_service_spec.rb
index 5b24b9b2a14..803b9a93be7 100644
--- a/spec/services/metrics/dashboard/default_embed_service_spec.rb
+++ b/spec/services/metrics/dashboard/default_embed_service_spec.rb
@@ -14,14 +14,16 @@ describe Metrics::Dashboard::DefaultEmbedService, :use_clean_rails_memory_store_
end
describe '#get_dashboard' do
- let(:service_params) { [project, user, { environment: environment, dashboard_path: nil }] }
+ let(:service_params) { [project, user, { environment: environment }] }
let(:service_call) { described_class.new(*service_params).get_dashboard }
it_behaves_like 'valid embedded dashboard service response'
it_behaves_like 'raises error for users with insufficient permissions'
it 'caches the unprocessed dashboard for subsequent calls' do
- expect(YAML).to receive(:safe_load).once.and_call_original
+ system_service = Metrics::Dashboard::SystemDashboardService
+
+ expect(system_service).to receive(:new).once.and_call_original
described_class.new(*service_params).get_dashboard
described_class.new(*service_params).get_dashboard
diff --git a/spec/support/helpers/features/notes_helpers.rb b/spec/support/helpers/features/notes_helpers.rb
index a2d8d71b541..8c27f81930d 100644
--- a/spec/support/helpers/features/notes_helpers.rb
+++ b/spec/support/helpers/features/notes_helpers.rb
@@ -23,6 +23,14 @@ module Spec
end
end
+ def edit_note(note_text_to_edit, new_note_text)
+ page.within('#notes-list li.note', text: note_text_to_edit) do
+ find('.js-note-edit').click
+ fill_in('note[note]', with: new_note_text)
+ find('.js-comment-button').click
+ end
+ end
+
def preview_note(text)
page.within('.js-main-target-form') do
filled_text = fill_in('note[note]', with: text)
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index ae1b859ae3f..d86371d70b9 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -3,6 +3,8 @@
module GraphqlHelpers
MutationDefinition = Struct.new(:query, :variables)
+ NoData = Class.new(StandardError)
+
# makes an underscored string look like a fieldname
# "merge_request" => "mergeRequest"
def self.fieldnamerize(underscored_field_name)
@@ -158,8 +160,9 @@ module GraphqlHelpers
post_graphql(mutation.query, current_user: current_user, variables: mutation.variables)
end
+ # Raises an error if no data is found
def graphql_data
- json_response['data']
+ json_response['data'] || (raise NoData, graphql_errors)
end
def graphql_errors
@@ -173,8 +176,9 @@ module GraphqlHelpers
end
end
+ # Raises an error if no response is found
def graphql_mutation_response(mutation_name)
- graphql_data[GraphqlHelpers.fieldnamerize(mutation_name)]
+ graphql_data.fetch(GraphqlHelpers.fieldnamerize(mutation_name))
end
def nested_fields?(field)
diff --git a/spec/support/shared_examples/application_setting_examples.rb b/spec/support/shared_examples/application_setting_examples.rb
index 2c600785ad3..0e6a8059376 100644
--- a/spec/support/shared_examples/application_setting_examples.rb
+++ b/spec/support/shared_examples/application_setting_examples.rb
@@ -40,6 +40,11 @@ RSpec.shared_examples 'string of domains' do |attribute|
setting.method("#{attribute}_raw=").call("example;34543:garbage:fdh5654;")
expect(setting.method(attribute).call).to contain_exactly('example', '34543:garbage:fdh5654')
end
+
+ it 'does not raise error with nil' do
+ setting.method("#{attribute}_raw=").call(nil)
+ expect(setting.method(attribute).call).to eq([])
+ end
end
RSpec.shared_examples 'application settings examples' do
@@ -75,6 +80,12 @@ RSpec.shared_examples 'application settings examples' do
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(ip_whitelist, domain_whitelist)
end
+
+ it 'does not raise error with nil' do
+ setting.outbound_local_requests_whitelist = nil
+
+ expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly([], [])
+ end
end
describe 'usage ping settings' do
diff --git a/spec/validators/qualified_domain_array_validator_spec.rb b/spec/validators/qualified_domain_array_validator_spec.rb
index a96b00bfd1d..6beb4c67f6f 100644
--- a/spec/validators/qualified_domain_array_validator_spec.rb
+++ b/spec/validators/qualified_domain_array_validator_spec.rb
@@ -19,20 +19,19 @@ describe QualifiedDomainArrayValidator do
subject { validator.validate(record) }
- shared_examples 'cannot be blank' do
- it 'returns error when attribute is blank' do
- record.domain_array = []
+ shared_examples 'can be nil' do
+ it 'allows when attribute is nil' do
+ record.domain_array = nil
subject
- expect(record.errors).to be_present
- expect(record.errors.first[1]).to eq 'entries cannot be blank'
+ expect(record.errors).to be_empty
end
end
- shared_examples 'can be nil' do
- it 'allows when attribute is nil' do
- record.domain_array = nil
+ shared_examples 'can be blank' do
+ it 'allows when attribute is blank' do
+ record.domain_array = []
subject
@@ -43,7 +42,7 @@ describe QualifiedDomainArrayValidator do
describe 'validations' do
let(:validator) { described_class.new(attributes: [:domain_array]) }
- it_behaves_like 'cannot be blank'
+ it_behaves_like 'can be blank'
it 'returns error when attribute is nil' do
record.domain_array = nil
@@ -51,6 +50,7 @@ describe QualifiedDomainArrayValidator do
subject
expect(record.errors).to be_present
+ expect(record.errors.first[1]).to eq('entries cannot be nil')
end
it 'allows when domain is valid' do
@@ -91,21 +91,13 @@ describe QualifiedDomainArrayValidator do
let(:validator) { described_class.new(attributes: [:domain_array], allow_nil: true) }
it_behaves_like 'can be nil'
-
- it_behaves_like 'cannot be blank'
+ it_behaves_like 'can be blank'
end
context 'when allow_blank is set to true' do
let(:validator) { described_class.new(attributes: [:domain_array], allow_blank: true) }
it_behaves_like 'can be nil'
-
- it 'allows when attribute is blank' do
- record.domain_array = []
-
- subject
-
- expect(record.errors).to be_empty
- end
+ it_behaves_like 'can be blank'
end
end
diff --git a/yarn.lock b/yarn.lock
index d0e43363977..6643b011dab 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -996,17 +996,16 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.67.0.tgz#c7b94eca13b99fd3aaa737fb6dcc0abc41d3c579"
integrity sha512-hJOmWEs6RkjzyKkb1vc9wwKGZIBIP0coHkxu/KgOoxhBVudpGk4CH7xJ6UuB2TKpb0SEh5CC1CzRZfBYaFhsaA==
-"@gitlab/ui@^5.9.0":
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.9.0.tgz#a38b1b57c365608b100b95969ae7a57ce1707542"
- integrity sha512-cgvEPWVerYZNLqkHjg5dd0VhEDBWj8aNoISZCaGOWI9K4yVtpMPVRUv19o/xYm4vUexfFsG9vg9lBgd+4ZU6Yw==
+"@gitlab/ui@^5.11.1":
+ version "5.11.1"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.11.1.tgz#10ee8a4410eb249032142f85f6180b6c465c48d7"
+ integrity sha512-bxIB3//aaYZIT6fpDKhIW60gvVvOCbw6inqC8xffQmklFYFKgcZjEIBu3RH5oJ6t3zFxeelcPQG7+t2F+p3bIg==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.2.1"
bootstrap "4.3.1"
- bootstrap-vue "^2.0.0-rc.26"
+ bootstrap-vue "2.0.0-rc.27"
copy-to-clipboard "^3.0.8"
- core-js "^2.6.9"
echarts "^4.2.0-rc.2"
highlight.js "^9.13.1"
js-beautify "^1.8.8"
@@ -2255,10 +2254,10 @@ bonjour@^3.5.0:
multicast-dns "^6.0.1"
multicast-dns-service-types "^1.1.0"
-bootstrap-vue@^2.0.0-rc.26:
- version "2.0.0-rc.26"
- resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.0.0-rc.26.tgz#2b8b9116a452584ae20ba8310d143635bc9e1375"
- integrity sha512-AzN+IRTmfR9rLFWNGt+v2XPmQjZiAlH4x5z2kStA3UoJ5LR91K34iZ8apaa6isDo+DfWDcwH4q7OwHM+VNxWwg==
+bootstrap-vue@2.0.0-rc.27:
+ version "2.0.0-rc.27"
+ resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.0.0-rc.27.tgz#884a46a71948d13c9729134cb564467f79a7b2b9"
+ integrity sha512-gXdpt2IsKbmC3SU0bf/RgldWwgrXK7G47yslOtkk4OA1z6fOzb2orM2vU5L8NCNZQomYax9LapRucv+8PByfdA==
dependencies:
"@nuxt/opencollective" "^0.2.2"
bootstrap "^4.3.1"
@@ -3236,21 +3235,16 @@ core-js-pure@3.1.4:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.4.tgz#5fa17dc77002a169a3566cc48dc774d2e13e3769"
integrity sha512-uJ4Z7iPNwiu1foygbcZYJsJs1jiXrTTCvxfLDXNhI/I+NHbSIEyr548y4fcsCEyWY0XgfAG/qqaunJ1SThHenA==
-core-js@^2.2.0, core-js@^2.6.9:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
- integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
+core-js@^2.2.0, core-js@~2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65"
+ integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU=
core-js@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.3.tgz#95700bca5f248f5f78c0ec63e784eca663ec4138"
integrity sha512-PWZ+ZfuaKf178BIAg+CRsljwjIMRV8MY00CbZczkR6Zk5LfkSkjGoaab3+bqRQWVITNZxQB7TFYz+CFcyuamvA==
-core-js@~2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65"
- integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU=
-
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"