summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.markdownlint.json1
-rw-r--r--CHANGELOG.md7
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/monitoring/components/graph_group.vue38
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_toggle_vuex.vue49
-rw-r--r--app/assets/stylesheets/pages/settings.scss10
-rw-r--r--app/controllers/admin/application_settings_controller.rb3
-rw-r--r--app/controllers/clusters/clusters_controller.rb13
-rw-r--r--app/controllers/projects/services_controller.rb27
-rw-r--r--app/helpers/application_settings_helper.rb4
-rw-r--r--app/helpers/events_helper.rb4
-rw-r--r--app/helpers/releases_helper.rb38
-rw-r--r--app/models/event.rb14
-rw-r--r--app/models/service.rb7
-rw-r--r--app/presenters/clusterable_presenter.rb4
-rw-r--r--app/presenters/event_presenter.rb20
-rw-r--r--app/presenters/instance_clusterable_presenter.rb4
-rw-r--r--app/views/clusters/clusters/cloud_providers/_cloud_provider_button.html.haml8
-rw-r--r--app/views/clusters/clusters/cloud_providers/_cloud_provider_selector.html.haml11
-rw-r--r--app/views/clusters/clusters/eks/_index.html.haml1
-rw-r--r--app/views/clusters/clusters/new.html.haml44
-rw-r--r--app/views/events/_event.atom.builder2
-rw-r--r--app/views/events/_event.html.haml2
-rw-r--r--app/views/events/_event_scope.html.haml5
-rw-r--r--app/views/events/event/_common.html.haml4
-rw-r--r--app/views/events/event/_created_project.html.haml2
-rw-r--r--app/views/projects/buttons/_fork.html.haml2
-rw-r--r--app/views/projects/releases/index.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/views/shared/notifications/_button.html.haml4
-rw-r--r--app/views/users/calendar_activities.html.haml2
-rw-r--r--changelogs/unreleased/60724-watch-button.yml5
-rw-r--r--changelogs/unreleased/api_settings.yml5
-rw-r--r--changelogs/unreleased/fj-11777-lower-search-count-limits.yml5
-rw-r--r--changelogs/unreleased/gitaly-version-v1.62.0.yml5
-rw-r--r--changelogs/unreleased/issue-67127.yml5
-rw-r--r--changelogs/unreleased/jivanvl-add-caret-icon-dashboard.yml5
-rw-r--r--changelogs/unreleased/kamil-improve-import-export.yml5
-rw-r--r--changelogs/unreleased/pl-project-service-json.yml5
-rw-r--r--config/gitlab.yml.example2
-rw-r--r--config/routes/repository.rb2
-rw-r--r--config/sidekiq_queues.yml1
-rw-r--r--db/migrate/20190826100605_add_group_column_to_events.rb14
-rw-r--r--db/schema.rb2
-rw-r--r--doc/administration/database_load_balancing.md6
-rw-r--r--doc/administration/index.md1
-rw-r--r--doc/administration/repository_storage_types.md2
-rw-r--r--doc/administration/smime_signing_email.md51
-rw-r--r--doc/api/projects.md6
-rw-r--r--doc/api/settings.md2
-rw-r--r--doc/api/tags.md9
-rw-r--r--doc/ci/variables/predefined_variables.md1
-rw-r--r--doc/development/changelog.md2
-rw-r--r--doc/development/code_review.md2
-rw-r--r--doc/development/distributed_tracing.md12
-rw-r--r--doc/development/documentation/styleguide.md41
-rw-r--r--doc/development/fe_guide/vuex.md2
-rw-r--r--doc/development/instrumentation.md4
-rw-r--r--doc/development/performance.md26
-rw-r--r--doc/development/testing_guide/frontend_testing.md15
-rw-r--r--doc/downgrade_ee_to_ce/README.md16
-rw-r--r--doc/install/aws/index.md6
-rw-r--r--doc/install/openshift_and_gitlab/index.md2
-rw-r--r--doc/integration/github.md2
-rw-r--r--doc/migrate_ci_to_ce/README.md3
-rw-r--r--doc/raketasks/backup_restore.md47
-rw-r--r--doc/raketasks/import.md10
-rw-r--r--doc/update/mysql_to_postgresql.md10
-rw-r--r--doc/user/application_security/dependency_scanning/index.md70
-rw-r--r--doc/user/application_security/index.md25
-rw-r--r--doc/user/clusters/applications.md42
-rw-r--r--doc/user/markdown.md2
-rw-r--r--doc/user/profile/account/create_accounts.md36
-rw-r--r--doc/user/profile/account/img/admin_user_button.pngbin0 -> 84870 bytes
-rw-r--r--doc/user/profile/account/img/admin_user_form.pngbin0 -> 196691 bytes
-rw-r--r--doc/user/profile/account/img/register_tab.pngbin0 -> 205561 bytes
-rw-r--r--doc/user/profile/index.md4
-rw-r--r--doc/user/project/canary_deployments.md2
-rw-r--r--doc/user/project/import/github.md29
-rw-r--r--doc/user/project/merge_requests/index.md5
-rw-r--r--doc/user/project/merge_requests/merge_request_approvals.md6
-rw-r--r--doc/user/project/pages/getting_started_part_four.md6
-rw-r--r--doc/workflow/lfs/lfs_administration.md6
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/api/helpers.rb6
-rw-r--r--lib/api/helpers/runner.rb2
-rw-r--r--lib/api/settings.rb8
-rw-r--r--lib/backup/manager.rb2
-rw-r--r--lib/banzai/filter/color_filter.rb2
-rw-r--r--lib/banzai/filter/external_link_filter.rb4
-rw-r--r--lib/banzai/filter/footnote_filter.rb4
-rw-r--r--lib/banzai/filter/math_filter.rb8
-rw-r--r--lib/banzai/filter/suggestion_filter.rb2
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb4
-rw-r--r--lib/banzai/issuable_extractor.rb4
-rw-r--r--lib/bitbucket/connection.rb4
-rw-r--r--lib/gitlab.rb4
-rw-r--r--lib/gitlab/import_export/attributes_finder.rb19
-rw-r--r--lib/gitlab/import_export/fast_hash_serializer.rb108
-rw-r--r--lib/gitlab/import_export/import_export.yml10
-rw-r--r--lib/gitlab/import_export/project_tree_saver.rb8
-rw-r--r--lib/gitlab/search_results.rb5
-rw-r--r--lib/google_api/cloud_platform/client.rb4
-rw-r--r--lib/quality/test_level.rb2
-rw-r--r--lib/system_check/app/init_script_up_to_date_check.rb2
-rw-r--r--lib/system_check/app/redis_version_check.rb2
-rw-r--r--lib/tasks/gitlab/graphql.rake4
-rw-r--r--lib/tasks/gitlab/uploads/legacy.rake2
-rw-r--r--locale/gitlab.pot22
-rw-r--r--qa/qa/page/project/issue/show.rb5
-rw-r--r--qa/qa/page/project/milestone/index.rb2
-rw-r--r--qa/qa/resource/issue.rb3
-rw-r--r--spec/controllers/admin/clusters_controller_spec.rb19
-rw-r--r--spec/controllers/groups/clusters_controller_spec.rb19
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb23
-rw-r--r--spec/controllers/projects/services_controller_spec.rb130
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb3
-rw-r--r--spec/features/projects/clusters_spec.rb24
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/tag.json3
-rw-r--r--spec/frontend/vue_shared/components/gl_toggle_vuex_spec.js115
-rw-r--r--spec/helpers/events_helper_spec.rb2
-rw-r--r--spec/helpers/releases_helper_spec.rb46
-rw-r--r--spec/javascripts/monitoring/components/graph_group_spec.js47
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/import_export/attributes_finder_spec.rb67
-rw-r--r--spec/lib/gitlab/import_export/config_spec.rb20
-rw-r--r--spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb272
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb53
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb6
-rw-r--r--spec/lib/gitlab/search_results_spec.rb17
-rw-r--r--spec/lib/gitlab/snippet_search_results_spec.rb4
-rw-r--r--spec/presenters/event_presenter_spec.rb41
-rw-r--r--spec/requests/api/settings_spec.rb38
-rw-r--r--spec/routing/project_routing_spec.rb70
-rw-r--r--spec/support/helpers/search_helpers.rb4
-rw-r--r--spec/support/import_export/import_export.yml4
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb54
137 files changed, 1847 insertions, 399 deletions
diff --git a/.markdownlint.json b/.markdownlint.json
index 2c40c0859f0..f06c0766c38 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -8,7 +8,6 @@
"style": "dash"
},
"line-length": false,
- "commands-show-output": false,
"no-duplicate-header": {
"allow_different_nesting": true
},
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a432b091c7e..e379c23ee3c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 12.2.5
+
+### Security (1 change)
+
+- Upgrade pages to 1.7.2.
+
+
## 12.2.4
### Fixed (7 changes)
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 91951fd8ad7..76d05362056 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-1.61.0
+1.62.0
diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue
index 0f5c5b3d60f..72ddd8d4fcf 100644
--- a/app/assets/javascripts/monitoring/components/graph_group.vue
+++ b/app/assets/javascripts/monitoring/components/graph_group.vue
@@ -1,5 +1,10 @@
<script>
+import Icon from '~/vue_shared/components/icon.vue';
+
export default {
+ components: {
+ Icon,
+ },
props: {
name: {
type: String,
@@ -15,15 +20,42 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ showGroup: true,
+ };
+ },
+ computed: {
+ caretIcon() {
+ return this.collapseGroup && this.showGroup ? 'angle-down' : 'angle-right';
+ },
+ },
+ created() {
+ this.showGroup = this.collapseGroup;
+ },
+ methods: {
+ collapse() {
+ this.showGroup = !this.showGroup;
+ },
+ },
};
</script>
<template>
<div v-if="showPanels" class="card prometheus-panel">
- <div class="card-header">
- <h4>{{ name }}</h4>
+ <div class="card-header d-flex align-items-center">
+ <h4 class="flex-grow-1">{{ name }}</h4>
+ <a role="button" @click="collapse">
+ <icon :size="16" :aria-label="__('Toggle collapse')" :name="caretIcon" />
+ </a>
+ </div>
+ <div
+ v-if="collapseGroup"
+ v-show="collapseGroup && showGroup"
+ class="card-body prometheus-graph-group"
+ >
+ <slot></slot>
</div>
- <div v-if="collapseGroup" class="card-body prometheus-graph-group"><slot></slot></div>
</div>
<div v-else class="prometheus-graph-group"><slot></slot></div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/gl_toggle_vuex.vue b/app/assets/javascripts/vue_shared/components/gl_toggle_vuex.vue
new file mode 100644
index 00000000000..b649dac029a
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/gl_toggle_vuex.vue
@@ -0,0 +1,49 @@
+<script>
+import { GlToggle } from '@gitlab/ui';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+
+export default {
+ name: 'GlToggleVuex',
+ components: {
+ GlToggle,
+ },
+ props: {
+ stateProperty: {
+ type: String,
+ required: true,
+ },
+ storeModule: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ setAction: {
+ type: String,
+ required: false,
+ default() {
+ return `set${capitalizeFirstCharacter(this.stateProperty)}`;
+ },
+ },
+ },
+ computed: {
+ value: {
+ get() {
+ const { state } = this.$store;
+ const { stateProperty, storeModule } = this;
+ return storeModule ? state[storeModule][stateProperty] : state[stateProperty];
+ },
+ set(value) {
+ const { stateProperty, storeModule, setAction } = this;
+ const action = storeModule ? `${storeModule}/${setAction}` : setAction;
+ this.$store.dispatch(action, { key: stateProperty, value });
+ },
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-toggle v-model="value">
+ <slot v-bind="{ value }"></slot>
+ </gl-toggle>
+</template>
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 79de1d78a6e..416537ef763 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -24,12 +24,16 @@
.settings {
// border-top for each item except the top one
- + .settings {
- border-top: 1px solid $border-color;
- }
+ border-top: 1px solid $border-color;
&:first-of-type {
margin-top: 10px;
+ border: 0;
+ }
+
+ + div .settings:first-of-type {
+ margin-top: 0;
+ border-top: 1px solid $border-color;
}
&.animating {
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 99411641874..f2f72bea5b4 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -85,7 +85,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
params[:application_setting][:import_sources]&.delete("")
params[:application_setting][:restricted_visibility_levels]&.delete("")
+ # TODO Remove domain_blacklist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-ce/issues/67204)
params.delete(:domain_blacklist_raw) if params[:domain_blacklist_file]
+ params.delete(:domain_blacklist_raw) if params[:domain_blacklist]
+ params.delete(:domain_whitelist_raw) if params[:domain_whitelist]
params.require(:application_setting).permit(
visible_application_setting_attributes
diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb
index ec8077d18e3..bcd771dafcf 100644
--- a/app/controllers/clusters/clusters_controller.rb
+++ b/app/controllers/clusters/clusters_controller.rb
@@ -35,6 +35,12 @@ class Clusters::ClustersController < Clusters::BaseController
end
def new
+ return unless Feature.enabled?(:create_eks_clusters)
+
+ @gke_selected = params[:provider] == 'gke'
+ @eks_selected = params[:provider] == 'eks'
+
+ return redirect_to @authorize_url if @gke_selected && @authorize_url && !@valid_gcp_token
end
# Overridding ActionController::Metal#status is NOT a good idea
@@ -99,7 +105,7 @@ class Clusters::ClustersController < Clusters::BaseController
validate_gcp_token
user_cluster
- render :new, locals: { active_tab: 'gcp' }
+ render :new, locals: { active_tab: 'create' }
end
end
@@ -116,7 +122,7 @@ class Clusters::ClustersController < Clusters::BaseController
validate_gcp_token
gcp_cluster
- render :new, locals: { active_tab: 'user' }
+ render :new, locals: { active_tab: 'add' }
end
end
@@ -189,7 +195,8 @@ class Clusters::ClustersController < Clusters::BaseController
end
def generate_gcp_authorize_url
- state = generate_session_key_redirect(clusterable.new_path.to_s)
+ params = Feature.enabled?(:create_eks_clusters) ? { provider: :gke } : {}
+ state = generate_session_key_redirect(clusterable.new_path(params).to_s)
@authorize_url = GoogleApi::CloudPlatform::Client.new(
nil, callback_google_api_auth_url,
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index e0df51590ae..c9f680a4696 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -18,10 +18,23 @@ class Projects::ServicesController < Projects::ApplicationController
def update
@service.attributes = service_params[:service]
- if @service.save(context: :manual_change)
- redirect_to(project_settings_integrations_path(@project), notice: success_message)
- else
- render 'edit'
+ saved = @service.save(context: :manual_change)
+
+ respond_to do |format|
+ format.html do
+ if saved
+ redirect_to project_settings_integrations_path(@project),
+ notice: success_message
+ else
+ render 'edit'
+ end
+ end
+
+ format.json do
+ status = saved ? :ok : :unprocessable_entity
+
+ render json: serialize_as_json, status: status
+ end
end
end
@@ -67,4 +80,10 @@ class Projects::ServicesController < Projects::ApplicationController
def ensure_service_enabled
render_404 unless service
end
+
+ def serialize_as_json
+ @service
+ .as_json(only: @service.json_fields)
+ .merge(errors: @service.errors.as_json)
+ end
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 84021d0da56..b1a6e988a1d 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -180,8 +180,12 @@ module ApplicationSettingsHelper
:default_projects_limit,
:default_snippet_visibility,
:disabled_oauth_sign_in_sources,
+ :domain_blacklist,
:domain_blacklist_enabled,
+ # TODO Remove domain_blacklist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-ce/issues/67204)
:domain_blacklist_raw,
+ :domain_whitelist,
+ # TODO Remove domain_whitelist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-ce/issues/67204)
:domain_whitelist_raw,
:outbound_local_requests_whitelist_raw,
:dsa_key_restriction,
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index e990e425cb6..09866ca75ff 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -103,7 +103,7 @@ module EventsHelper
words << "at"
end
- words << event.project_name
+ words << event.resource_parent_name
words.join(" ")
end
@@ -223,3 +223,5 @@ module EventsHelper
end
end
end
+
+EventsHelper.prepend_if_ee('EE::EventsHelper')
diff --git a/app/helpers/releases_helper.rb b/app/helpers/releases_helper.rb
new file mode 100644
index 00000000000..4d9fe345edf
--- /dev/null
+++ b/app/helpers/releases_helper.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module ReleasesHelper
+ IMAGE_PATH = 'illustrations/releases.svg'
+ DOCUMENTATION_PATH = 'user/project/releases/index'
+
+ def illustration
+ image_path(IMAGE_PATH)
+ end
+
+ def help_page
+ help_page_path(DOCUMENTATION_PATH)
+ end
+
+ def url_for_merge_requests
+ project_merge_requests_url(@project, params_for_issue_and_mr_paths)
+ end
+
+ def url_for_issues
+ project_issues_url(@project, params_for_issue_and_mr_paths)
+ end
+
+ def data_for_releases_page
+ {
+ project_id: @project.id,
+ illustration_path: illustration,
+ documentation_path: help_page,
+ merge_requests_url: url_for_merge_requests,
+ issues_url: url_for_issues
+ }
+ end
+
+ private
+
+ def params_for_issue_and_mr_paths
+ { scope: 'all', state: 'opened' }
+ end
+end
diff --git a/app/models/event.rb b/app/models/event.rb
index 52d54be39a9..580bb770599 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -3,6 +3,8 @@
class Event < ApplicationRecord
include Sortable
include FromUnion
+ include Presentable
+
default_scope { reorder(nil) }
CREATED = 1
@@ -135,6 +137,10 @@ class Event < ApplicationRecord
end
end
+ def present
+ super(presenter_class: ::EventPresenter)
+ end
+
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def visible_to_user?(user = nil)
@@ -161,12 +167,8 @@ class Event < ApplicationRecord
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Metrics/CyclomaticComplexity
- def project_name
- if project
- project.full_name
- else
- "(deleted project)"
- end
+ def resource_parent
+ project || group
end
def target_title
diff --git a/app/models/service.rb b/app/models/service.rb
index 431c5881460..d866a51c42e 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -107,6 +107,13 @@ class Service < ApplicationRecord
[]
end
+ # Expose a list of fields in the JSON endpoint.
+ #
+ # This list is used in `Service#as_json(only: json_fields)`.
+ def json_fields
+ %w(active)
+ end
+
def test_data(project, user)
Gitlab::DataBuilder::Push.build_sample(project, user)
end
diff --git a/app/presenters/clusterable_presenter.rb b/app/presenters/clusterable_presenter.rb
index d1bf0344b66..49c64b31fc7 100644
--- a/app/presenters/clusterable_presenter.rb
+++ b/app/presenters/clusterable_presenter.rb
@@ -25,8 +25,8 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated
polymorphic_path([clusterable, :clusters])
end
- def new_path
- new_polymorphic_path([clusterable, :cluster])
+ def new_path(options = {})
+ new_polymorphic_path([clusterable, :cluster], options)
end
def create_user_clusters_path
diff --git a/app/presenters/event_presenter.rb b/app/presenters/event_presenter.rb
new file mode 100644
index 00000000000..f31d362d5fa
--- /dev/null
+++ b/app/presenters/event_presenter.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class EventPresenter < Gitlab::View::Presenter::Delegated
+ presents :event
+
+ def resource_parent_name
+ resource_parent&.full_name || ''
+ end
+
+ def target_link_options
+ case resource_parent
+ when Group
+ [event.group, event.target]
+ when Project
+ [event.project.namespace.becomes(Namespace), event.project, event.target]
+ else
+ ''
+ end
+ end
+end
diff --git a/app/presenters/instance_clusterable_presenter.rb b/app/presenters/instance_clusterable_presenter.rb
index f8bbe5216f1..cce400ad2a1 100644
--- a/app/presenters/instance_clusterable_presenter.rb
+++ b/app/presenters/instance_clusterable_presenter.rb
@@ -18,8 +18,8 @@ class InstanceClusterablePresenter < ClusterablePresenter
end
override :new_path
- def new_path
- new_admin_cluster_path
+ def new_path(options = {})
+ new_admin_cluster_path(options)
end
override :cluster_status_cluster_path
diff --git a/app/views/clusters/clusters/cloud_providers/_cloud_provider_button.html.haml b/app/views/clusters/clusters/cloud_providers/_cloud_provider_button.html.haml
new file mode 100644
index 00000000000..f707c6585ec
--- /dev/null
+++ b/app/views/clusters/clusters/cloud_providers/_cloud_provider_button.html.haml
@@ -0,0 +1,8 @@
+- provider = local_assigns.fetch(:provider)
+- logo_path = local_assigns.fetch(:logo_path)
+- label = local_assigns.fetch(:label)
+
+= link_to clusterable.new_path(provider: provider), class: 'btn gl-button btn-outline flex-fill d-inline-flex flex-column mr-3 justify-content-center align-items-center' do
+ = image_tag logo_path, alt: label, class: 'gl-w-13 gl-h-13'
+ %span
+ = label
diff --git a/app/views/clusters/clusters/cloud_providers/_cloud_provider_selector.html.haml b/app/views/clusters/clusters/cloud_providers/_cloud_provider_selector.html.haml
new file mode 100644
index 00000000000..24506205243
--- /dev/null
+++ b/app/views/clusters/clusters/cloud_providers/_cloud_provider_selector.html.haml
@@ -0,0 +1,11 @@
+- gke_label = s_('ClusterIntegration|Google GKE')
+- eks_label = s_('ClusterIntegration|Amazon EKS')
+- create_cluster_label = s_('ClusterIntegration|Create cluster on')
+.d-flex.flex-column
+ %h5
+ = create_cluster_label
+ .d-flex
+ = render partial: 'clusters/clusters/cloud_providers/cloud_provider_button',
+ locals: { provider: 'gke', label: gke_label, logo_path: '' }
+ = render partial: 'clusters/clusters/cloud_providers/cloud_provider_button',
+ locals: { provider: 'eks', label: eks_label, logo_path: '' }
diff --git a/app/views/clusters/clusters/eks/_index.html.haml b/app/views/clusters/clusters/eks/_index.html.haml
new file mode 100644
index 00000000000..ca8e9ba527a
--- /dev/null
+++ b/app/views/clusters/clusters/eks/_index.html.haml
@@ -0,0 +1 @@
+.js-create-eks-cluster-form-container
diff --git a/app/views/clusters/clusters/new.html.haml b/app/views/clusters/clusters/new.html.haml
index 6a8af23e5e8..fb182d99ff0 100644
--- a/app/views/clusters/clusters/new.html.haml
+++ b/app/views/clusters/clusters/new.html.haml
@@ -1,6 +1,8 @@
- breadcrumb_title _('Kubernetes')
- page_title _('Kubernetes Cluster')
-- active_tab = local_assigns.fetch(:active_tab, 'gcp')
+- create_eks_enabled = Feature.enabled?(:create_eks_clusters)
+- active_tab = local_assigns.fetch(:active_tab, 'create')
+- link_end = '<a/>'.html_safe
= javascript_include_tag 'https://apis.google.com/js/api.js'
= render_gcp_signup_offer
@@ -11,26 +13,36 @@
.col-md-9.js-toggle-container
%ul.nav-links.nav-tabs.gitlab-tabs.nav{ role: 'tablist' }
%li.nav-item{ role: 'presentation' }
- %a.nav-link{ href: '#create-gcp-cluster-pane', id: 'create-gcp-cluster-tab', class: active_when(active_tab == 'gcp'), data: { toggle: 'tab' }, role: 'tab' }
+ %a.nav-link{ href: '#create-cluster-pane', id: 'create-cluster-tab', class: active_when(active_tab == 'create'), data: { toggle: 'tab' }, role: 'tab' }
%span Create new Cluster on GKE
%li.nav-item{ role: 'presentation' }
- %a.nav-link{ href: '#add-user-cluster-pane', id: 'add-user-cluster-tab', class: active_when(active_tab == 'user'), data: { toggle: 'tab' }, role: 'tab' }
+ %a.nav-link{ href: '#add-cluster-pane', id: 'add-cluster-tab', class: active_when(active_tab == 'add'), data: { toggle: 'tab' }, role: 'tab' }
%span Add existing cluster
.tab-content.gitlab-tab-content
- .tab-pane{ id: 'create-gcp-cluster-pane', class: active_when(active_tab == 'gcp'), role: 'tabpanel' }
- = render 'clusters/clusters/gcp/header'
- - if @valid_gcp_token
- = render 'clusters/clusters/gcp/form'
- - elsif @authorize_url
- .signin-with-google
- = link_to(image_tag('auth_buttons/signin_with_google.png', width: '191px'), @authorize_url)
- = _('or')
- = link_to('create a new Google account', 'https://accounts.google.com/SignUpWithoutGmail?service=cloudconsole&continue=https%3A%2F%2Fconsole.cloud.google.com%2Ffreetrial%3Futm_campaign%3D2018_cpanel%26utm_source%3Dgitlab%26utm_medium%3Dreferral', target: '_blank', rel: 'noopener noreferrer')
- - else
- - link = link_to(s_('ClusterIntegration|properly configured'), help_page_path("integration/google"), target: '_blank', rel: 'noopener noreferrer')
- = s_('Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service.').html_safe % { link_to_documentation: link }
+ - if create_eks_enabled
+ .tab-pane{ id: 'create-cluster-pane', class: active_when(active_tab == 'create'), role: 'tabpanel' }
+ - if @gke_selected && @valid_gcp_token
+ = render 'clusters/clusters/gcp/header'
+ = render 'clusters/clusters/gcp/form'
+ - elsif @eks_selected
+ = render 'clusters/clusters/eks/index'
+ - else
+ = render 'clusters/clusters/cloud_providers/cloud_provider_selector'
+ - else
+ .tab-pane{ id: 'create-cluster-pane', class: active_when(active_tab == 'create'), role: 'tabpanel' }
+ = render 'clusters/clusters/gcp/header'
+ - if @valid_gcp_token
+ = render 'clusters/clusters/gcp/form'
+ - elsif @authorize_url
+ .signin-with-google
+ - create_account_link = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: 'https://accounts.google.com/SignUpWithoutGmail?service=cloudconsole&continue=https%3A%2F%2Fconsole.cloud.google.com%2Ffreetrial%3Futm_campaign%3D2018_cpanel%26utm_source%3Dgitlab%26utm_medium%3Dreferral' }
+ = link_to(image_tag('auth_buttons/signin_with_google.png', width: '191px', alt: _('Sign in with Google')), @authorize_url)
+ = s_('or %{link_start}create a new Google account%{link_end}').html_safe % { link_start: create_account_link, link_end: link_end }
+ - else
+ - documentation_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path("integration/google") }
+ = s_('Google authentication is not %{link_start}property configured%{link_end}. Ask your GitLab administrator if you want to use this service.').html_safe % { link_start: documentation_link_start, link_end: link_end }
- .tab-pane{ id: 'add-user-cluster-pane', class: active_when(active_tab == 'user'), role: 'tabpanel' }
+ .tab-pane{ id: 'add-cluster-pane', class: active_when(active_tab == 'add'), role: 'tabpanel' }
= render 'clusters/clusters/user/header'
= render 'clusters/clusters/user/form'
diff --git a/app/views/events/_event.atom.builder b/app/views/events/_event.atom.builder
index d56234e6c1a..406e8a93194 100644
--- a/app/views/events/_event.atom.builder
+++ b/app/views/events/_event.atom.builder
@@ -1,5 +1,7 @@
return unless event.visible_to_user?(current_user)
+event = event.present
+
xml.entry do
xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
xml.link href: event_feed_url(event)
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 222175c818a..647f0597adb 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -1,3 +1,5 @@
+- event = event.present
+
- if event.visible_to_user?(current_user)
.event-item
.event-item-timestamp
diff --git a/app/views/events/_event_scope.html.haml b/app/views/events/_event_scope.html.haml
index 98941722434..67e4c538b4a 100644
--- a/app/views/events/_event_scope.html.haml
+++ b/app/views/events/_event_scope.html.haml
@@ -2,6 +2,5 @@
= event_preposition(event)
- if event.project
= link_to_project(event.project)
- - else
- = event.project_name
-
+ - elsif event.group
+ = link_to event.resource_parent_name, group_path(event.group)
diff --git a/app/views/events/event/_common.html.haml b/app/views/events/event/_common.html.haml
index b02fdb4b638..50c5885c648 100644
--- a/app/views/events/event/_common.html.haml
+++ b/app/views/events/event/_common.html.haml
@@ -8,7 +8,7 @@
%span.event-type.d-inline-block.append-right-4{ class: event.action_name }
= event.action_name
%span.event-target-type.append-right-4= event.target_type.titleize.downcase
- = link_to [event.project.namespace.becomes(Namespace), event.project, event.target], class: 'has-tooltip event-target-link append-right-4', title: event.target_title do
+ = link_to event.target_link_options, class: 'has-tooltip event-target-link append-right-4', title: event.target_title do
= event.target.reference_link_text
- unless event.milestone?
%span.event-target-title.append-right-4{ dir: "auto" }
@@ -17,4 +17,4 @@
%span.event-type.d-inline-block.append-right-4{ class: event.action_name }
= event_action_name(event)
- = render "events/event_scope", event: event
+ = render "events/event_scope", event: event if event.resource_parent.present?
diff --git a/app/views/events/event/_created_project.html.haml b/app/views/events/event/_created_project.html.haml
index 2f156603414..606b0febb57 100644
--- a/app/views/events/event/_created_project.html.haml
+++ b/app/views/events/event/_created_project.html.haml
@@ -10,4 +10,4 @@
- if event.project
= link_to_project(event.project)
- else
- = event.project_name
+ = event.resource_parent_name
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index bc0a89bea62..4b82eb2c5ef 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -8,7 +8,7 @@
- else
- can_create_fork = current_user.can?(:create_fork)
= link_to new_project_fork_path(@project),
- class: "btn btn-default has-tooltip count-badge-button d-flex align-items-center fork-btn #{'has-tooltip disabled' unless can_create_fork}",
+ class: "btn btn-default btn-xs has-tooltip count-badge-button d-flex align-items-center fork-btn #{'has-tooltip disabled' unless can_create_fork}",
title: (s_('ProjectOverview|You have reached your project limit') unless can_create_fork) do
= sprite_icon('fork', { css_class: 'icon' })
%span= s_('ProjectOverview|Fork')
diff --git a/app/views/projects/releases/index.html.haml b/app/views/projects/releases/index.html.haml
index 326b83c856e..4d5b8cc80f7 100644
--- a/app/views/projects/releases/index.html.haml
+++ b/app/views/projects/releases/index.html.haml
@@ -1,3 +1,3 @@
- page_title _('Releases')
-#js-releases-page{ data: { project_id: @project.id, illustration_path: image_path('illustrations/releases.svg'), documentation_path: help_page_path('user/project/releases/index') } }
+#js-releases-page{ data: data_for_releases_page }
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 837707707a9..3b26b8df8a1 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -41,7 +41,7 @@
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { track_label: "right_sidebar", track_property: "milestone", track_event: "click_edit_button", track_value: "" }
.value.hide-collapsed
- if milestone.present?
- = link_to milestone[:title], milestone[:web_url], class: "bold has-tooltip", title: sidebar_milestone_remaining_days(milestone), data: { container: "body", html: 'true', boundary: 'viewport' }
+ = link_to milestone[:title], milestone[:web_url], class: "bold has-tooltip", title: sidebar_milestone_remaining_days(milestone), data: { container: "body", html: 'true', boundary: 'viewport', qa_selector: 'milestone_link' }
- else
%span.no-value
= _('None')
diff --git a/app/views/shared/notifications/_button.html.haml b/app/views/shared/notifications/_button.html.haml
index b4266937a4e..441abd57334 100644
--- a/app/views/shared/notifications/_button.html.haml
+++ b/app/views/shared/notifications/_button.html.haml
@@ -17,14 +17,14 @@
.js-notification-toggle-btns
%div{ class: ("btn-group" if notification_setting.custom?) }
- if notification_setting.custom?
- %button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn.text-left#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
+ %button.dropdown-new.btn.btn-default.btn-xs.has-tooltip.notifications-btn.text-left#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
= icon("bell", class: "js-notification-loading")
= notification_title(notification_setting.level)
%button.btn.dropdown-toggle{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
= icon('caret-down')
.sr-only Toggle dropdown
- else
- %button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
+ %button.dropdown-new.btn.btn-default.btn-xs.has-tooltip.notifications-btn#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
.float-left
= icon("bell", class: "js-notification-loading")
= notification_title(notification_setting.level)
diff --git a/app/views/users/calendar_activities.html.haml b/app/views/users/calendar_activities.html.haml
index 3191eaa1e2c..7516dfe1602 100644
--- a/app/views/users/calendar_activities.html.haml
+++ b/app/views/users/calendar_activities.html.haml
@@ -27,7 +27,7 @@
- if event.project
= link_to_project(event.project)
- else
- = event.project_name
+ = event.resource_parent_name
- else
made a private contribution
- else
diff --git a/changelogs/unreleased/60724-watch-button.yml b/changelogs/unreleased/60724-watch-button.yml
new file mode 100644
index 00000000000..f22f7708ed2
--- /dev/null
+++ b/changelogs/unreleased/60724-watch-button.yml
@@ -0,0 +1,5 @@
+---
+title: Fix watch button styling and notifications buttons consistency
+merge_request: 32827
+author:
+type: fixed
diff --git a/changelogs/unreleased/api_settings.yml b/changelogs/unreleased/api_settings.yml
new file mode 100644
index 00000000000..58830a5ab97
--- /dev/null
+++ b/changelogs/unreleased/api_settings.yml
@@ -0,0 +1,5 @@
+---
+title: Improve application settings API
+merge_request: 31149
+author: Mathieu Parent
+type: fixed
diff --git a/changelogs/unreleased/fj-11777-lower-search-count-limits.yml b/changelogs/unreleased/fj-11777-lower-search-count-limits.yml
new file mode 100644
index 00000000000..c284bc49bfc
--- /dev/null
+++ b/changelogs/unreleased/fj-11777-lower-search-count-limits.yml
@@ -0,0 +1,5 @@
+---
+title: Lower search counters
+merge_request: 11777
+author:
+type: performance
diff --git a/changelogs/unreleased/gitaly-version-v1.62.0.yml b/changelogs/unreleased/gitaly-version-v1.62.0.yml
new file mode 100644
index 00000000000..6ae200bd7f4
--- /dev/null
+++ b/changelogs/unreleased/gitaly-version-v1.62.0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade to Gitaly v1.62.0
+merge_request: 32608
+author:
+type: changed
diff --git a/changelogs/unreleased/issue-67127.yml b/changelogs/unreleased/issue-67127.yml
new file mode 100644
index 00000000000..70848dc6ff9
--- /dev/null
+++ b/changelogs/unreleased/issue-67127.yml
@@ -0,0 +1,5 @@
+---
+title: Expose 'protected' field for Tag API endpoint.
+merge_request: 32790
+author: Andrea Leone
+type: added
diff --git a/changelogs/unreleased/jivanvl-add-caret-icon-dashboard.yml b/changelogs/unreleased/jivanvl-add-caret-icon-dashboard.yml
new file mode 100644
index 00000000000..148e306c3b8
--- /dev/null
+++ b/changelogs/unreleased/jivanvl-add-caret-icon-dashboard.yml
@@ -0,0 +1,5 @@
+---
+title: Add caret icons to the monitoring dashboard
+merge_request: 32239
+author:
+type: changed
diff --git a/changelogs/unreleased/kamil-improve-import-export.yml b/changelogs/unreleased/kamil-improve-import-export.yml
new file mode 100644
index 00000000000..9d485e0df2d
--- /dev/null
+++ b/changelogs/unreleased/kamil-improve-import-export.yml
@@ -0,0 +1,5 @@
+---
+title: Reduce N+1 when doing project export
+merge_request: 32423
+author:
+type: performance
diff --git a/changelogs/unreleased/pl-project-service-json.yml b/changelogs/unreleased/pl-project-service-json.yml
new file mode 100644
index 00000000000..a273289d871
--- /dev/null
+++ b/changelogs/unreleased/pl-project-service-json.yml
@@ -0,0 +1,5 @@
+---
+title: Expose update project service endpoint JSON
+merge_request: 32759
+author:
+type: added
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index aa7c2d343a8..87159b695f9 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -342,7 +342,7 @@ production: &base
## Sidekiq
sidekiq:
- log_format: default # (json is also supported)
+ log_format: json # (default is the original format)
## Auxiliary jobs
# Periodically executed jobs, to self-heal GitLab, do external synchronizations, etc.
diff --git a/config/routes/repository.rb b/config/routes/repository.rb
index b89e1c7f9af..093b86f3259 100644
--- a/config/routes/repository.rb
+++ b/config/routes/repository.rb
@@ -65,7 +65,7 @@ scope format: false do
resources :protected_tags, only: [:index, :show, :create, :update, :destroy]
end
- scope constraints: { id: /.+/ } do
+ scope constraints: { id: /[^\0]+/ } do
scope controller: :blob do
get '/new/*id', action: :new, as: :new_blob
post '/create/*id', action: :create, as: :create_blob
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index e89e9657314..f37cd518d48 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -116,3 +116,4 @@
- [incident_management, 2]
- [jira_connect, 1]
- [update_external_pull_requests, 3]
+ - [refresh_license_compliance_checks, 2]
diff --git a/db/migrate/20190826100605_add_group_column_to_events.rb b/db/migrate/20190826100605_add_group_column_to_events.rb
index cd7b2b1d96a..dfc9d8cbdf1 100644
--- a/db/migrate/20190826100605_add_group_column_to_events.rb
+++ b/db/migrate/20190826100605_add_group_column_to_events.rb
@@ -1,9 +1,19 @@
# frozen_string_literal: true
class AddGroupColumnToEvents < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
DOWNTIME = false
- def change
- add_reference :events, :group, index: true, foreign_key: { to_table: :namespaces, on_delete: :cascade }
+ disable_ddl_transaction!
+
+ def up
+ add_column(:events, :group_id, :bigint) unless column_exists?(:events, :group_id)
+ add_concurrent_index(:events, :group_id)
+ add_concurrent_foreign_key(:events, :namespaces, column: :group_id, on_delete: :cascade)
+ end
+
+ def down
+ remove_column(:events, :group_id) if column_exists?(:events, :group_id)
end
end
diff --git a/db/schema.rb b/db/schema.rb
index 6ddfb8bcb39..70f3a42e7f8 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -3864,7 +3864,7 @@ ActiveRecord::Schema.define(version: 2019_09_05_223900) do
add_foreign_key "epics", "users", column: "assignee_id", name: "fk_dccd3f98fc", on_delete: :nullify
add_foreign_key "epics", "users", column: "author_id", name: "fk_3654b61b03", on_delete: :cascade
add_foreign_key "epics", "users", column: "closed_by_id", name: "fk_aa5798e761", on_delete: :nullify
- add_foreign_key "events", "namespaces", column: "group_id", on_delete: :cascade
+ add_foreign_key "events", "namespaces", column: "group_id", name: "fk_61fbf6ca48", on_delete: :cascade
add_foreign_key "events", "projects", on_delete: :cascade
add_foreign_key "events", "users", column: "author_id", name: "fk_edfd187b6f", on_delete: :cascade
add_foreign_key "external_pull_requests", "projects", on_delete: :cascade
diff --git a/doc/administration/database_load_balancing.md b/doc/administration/database_load_balancing.md
index f643d853d10..6620989983f 100644
--- a/doc/administration/database_load_balancing.md
+++ b/doc/administration/database_load_balancing.md
@@ -148,9 +148,9 @@ The following options can be set:
If `record_type` is set to `SRV`, GitLab will continue to use a round-robin algorithm
and will ignore the `weight` and `priority` in the record. Since SRV records usually
return hostnames instead of IPs, GitLab will look for the IPs of returned hostnames
-in the additional section of the SRV response. If no IP is found for a hostname, Gitlab
-will query the configured `nameserver` for ANY record for each such hostname looking for A or AAAA records, eventually
-dropping this hostname from rotation if it can't resolve its IP.
+in the additional section of the SRV response. If no IP is found for a hostname, GitLab
+will query the configured `nameserver` for ANY record for each such hostname looking for A or AAAA
+records, eventually dropping this hostname from rotation if it can't resolve its IP.
The `interval` value specifies the _minimum_ time between checks. If the A
record has a TTL greater than this value, then service discovery will honor said
diff --git a/doc/administration/index.md b/doc/administration/index.md
index d557068e6c8..b58291b7478 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -104,6 +104,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
## User settings and permissions
+- [Creating users](../user/profile/account/create_accounts.md): Create users manually or through authentication integrations.
- [Libravatar](../customization/libravatar.md): Use Libravatar instead of Gravatar for user avatars.
- [Sign-up restrictions](../user/admin_area/settings/sign_up_restrictions.md): block email addresses of specific domains, or whitelist only specific domains.
- [Access restrictions](../user/admin_area/settings/visibility_and_access_controls.md#enabled-git-access-protocols): Define which Git access protocols can be used to talk to GitLab (SSH, HTTP, HTTPS).
diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md
index 3ee8673b297..d2d7ebdd634 100644
--- a/doc/administration/repository_storage_types.md
+++ b/doc/administration/repository_storage_types.md
@@ -10,7 +10,7 @@ that can be:
- Mounted to the local disk
- Exposed as an NFS shared volume
-- Acessed via [gitaly] on its own machine.
+- Accessed via [gitaly] on its own machine.
In GitLab, this is configured in `/etc/gitlab/gitlab.rb` by the `git_data_dirs({})`
configuration hash. The storage layouts discussed here will apply to any shard
diff --git a/doc/administration/smime_signing_email.md b/doc/administration/smime_signing_email.md
index b2e3bf8487b..530553ec1c4 100644
--- a/doc/administration/smime_signing_email.md
+++ b/doc/administration/smime_signing_email.md
@@ -11,29 +11,56 @@ S/MIME signs and/or encrypts the message itself
## Enable S/MIME signing
This setting must be explicitly enabled and a single pair of key and certificate
-files must be provided in `gitlab.rb` or `gitlab.yml` if you are using Omnibus
-GitLab or installed GitLab from source respectively:
-
-```yaml
-email_smime:
- enabled: true
- key_file: /etc/pki/smime/private/gitlab.key
- cert_file: /etc/pki/smime/certs/gitlab.crt
-```
+files must be provided:
-- Both files must be provided PEM-encoded.
-- The key file must be unencrypted so that Gitlab can read it without user
+- Both files must be PEM-encoded.
+- The key file must be unencrypted so that GitLab can read it without user
intervention.
+- Only RSA keys are supported.
NOTE: **Note:** Be mindful of the access levels for your private keys and visibility to
third parties.
+**For Omnibus installations:**
+
+1. Edit `/etc/gitlab/gitlab.rb` and adapt the file paths:
+
+ ```ruby
+ gitlab_rails['gitlab_email_smime_enabled'] = true
+ gitlab_rails['gitlab_email_smime_key_file'] = '/etc/gitlab/ssl/gitlab_smime.key'
+ gitlab_rails['gitlab_email_smime_cert_file'] = '/etc/gitlab/ssl/gitlab_smime.crt'
+ ```
+
+1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+
+NOTE: **Note:** The key needs to be readable by the GitLab system user (`git` by default).
+
+**For installations from source:**
+
+1. Edit `config/gitlab.yml`:
+
+ ```yaml
+ email_smime:
+ # Uncomment and set to true if you need to enable email S/MIME signing (default: false)
+ enabled: true
+ # S/MIME private key file in PEM format, unencrypted
+ # Default is '.gitlab_smime_key' relative to Rails.root (i.e. root of the GitLab app).
+ key_file: /etc/pki/smime/private/gitlab.key
+ # S/MIME public certificate key in PEM format, will be attached to signed messages
+ # Default is '.gitlab_smime_cert' relative to Rails.root (i.e. root of the GitLab app).
+ cert_file: /etc/pki/smime/certs/gitlab.crt
+ ```
+
+1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect.
+
+NOTE: **Note:** The key needs to be readable by the GitLab system user (`git` by default).
+
### How to convert S/MIME PKCS#12 / PFX format to PEM encoding
Typically S/MIME certificates are handled in binary PKCS#12 format (`.pfx` or `.p12`
extensions), which contain the following in a single encrypted file:
-- Server certificate
+- Public certificate
- Intermediate certificates (if any)
- Private key
diff --git a/doc/api/projects.md b/doc/api/projects.md
index cf28ea84704..3ea1434d5ca 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -929,7 +929,7 @@ POST /projects
| `ci_config_path` | string | no | The path to CI config file |
| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for this project |
| `auto_devops_deploy_strategy` | string | no | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`) |
-| `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins |
+| `repository_storage` | string | no | **(STARTER ONLY)** Which storage shard the repository is on. Available only to admins |
| `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge requests by default |
| `mirror` | boolean | no | **(STARTER)** Enables pull mirroring in a project |
| `mirror_trigger_builds` | boolean | no | **(STARTER)** Pull mirroring triggers builds |
@@ -986,7 +986,7 @@ POST /projects/user/:user_id
| `ci_config_path` | string | no | The path to CI config file |
| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for this project |
| `auto_devops_deploy_strategy` | string | no | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`) |
-| `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins |
+| `repository_storage` | string | no | **(STARTER ONLY)** Which storage shard the repository is on. Available only to admins |
| `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge requests by default |
| `external_authorization_classification_label` | string | no | **(PREMIUM)** The classification label for the project |
| `mirror` | boolean | no | **(STARTER)** Enables pull mirroring in a project |
@@ -1043,7 +1043,7 @@ PUT /projects/:id
| `ci_default_git_depth` | integer | no | Default number of revisions for [shallow cloning](../user/project/pipelines/settings.md#git-shallow-clone) |
| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for this project |
| `auto_devops_deploy_strategy` | string | no | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`) |
-| `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins |
+| `repository_storage` | string | no | **(STARTER ONLY)** Which storage shard the repository is on. Available only to admins |
| `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge request by default |
| `external_authorization_classification_label` | string | no | **(PREMIUM)** The classification label for the project |
| `mirror` | boolean | no | **(STARTER)** Enables pull mirroring in a project |
diff --git a/doc/api/settings.md b/doc/api/settings.md
index a14b0d3632a..4ad4ebdacb6 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -210,7 +210,7 @@ are listed in the descriptions of the relevant settings.
| `diff_max_patch_bytes` | integer | no | Maximum diff patch size (Bytes). |
| `disabled_oauth_sign_in_sources` | array of strings | no | Disabled OAuth sign-in sources. |
| `dns_rebinding_protection_enabled` | boolean | no | Enforce DNS rebinding attack protection. |
-| `domain_blacklist` | array of strings | required by: `domain_blacklist_enabled` | Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: `domain.com`, `*.domain.com`. |
+| `domain_blacklist` | array of strings | no | Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: `domain.com`, `*.domain.com`. |
| `domain_blacklist_enabled` | boolean | no | (**If enabled, requires:** `domain_blacklist`) Allows blocking sign-ups from emails from specific domains. |
| `domain_whitelist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is `null`, meaning there is no restriction. |
| `dsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded DSA key. Default is `0` (no restriction). `-1` disables DSA keys. |
diff --git a/doc/api/tags.md b/doc/api/tags.md
index 1d874fea1f8..88f63d6b34b 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -46,7 +46,8 @@ Parameters:
},
"name": "v1.0.0",
"target": "2695effb5807a22ff3d138d593fd856244e155e7",
- "message": null
+ "message": null,
+ "protected": true
}
]
```
@@ -94,7 +95,8 @@ Example Response:
"committer_email": "contact@arthurverschaeve.be",
"committed_date": "2015-02-01T21:56:31.000+01:00"
},
- "release": null
+ "release": null,
+ "protected": false
}
```
@@ -138,7 +140,8 @@ Parameters:
},
"name": "v1.0.0",
"target": "2695effb5807a22ff3d138d593fd856244e155e7",
- "message": null
+ "message": null,
+ "protected": false
}
```
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index 409f7d62538..a3c253cc517 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -100,6 +100,7 @@ future GitLab releases.**
| `CI_RUNNER_REVISION` | all | 10.6 | GitLab Runner revision that is executing the current job |
| `CI_RUNNER_TAGS` | 8.10 | 0.5 | The defined runner tags |
| `CI_RUNNER_VERSION` | all | 10.6 | GitLab Runner version that is executing the current job |
+| `CI_RUNNER_SHORT_TOKEN` | all | 12.3 | First eight characters of GitLab Runner's token used to authenticate new job requests. Used as Runner's unique ID |
| `CI_SERVER` | all | all | Mark that job is executed in CI environment |
| `CI_SERVER_HOST` | 12.1 | all | Host component of the GitLab instance URL, without protocol and port (like gitlab.example.com) |
| `CI_SERVER_NAME` | all | all | The name of CI server that is used to coordinate jobs |
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index 814624c7586..5667f58b0c3 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -99,7 +99,7 @@ automatically.
Its simplest usage is to provide the value for `title`:
```text
-$ bin/changelog 'Hey DZ, I added a feature to GitLab!'
+bin/changelog 'Hey DZ, I added a feature to GitLab!'
```
At this point the script would ask you to select the category of the change (mapped to the `type` field in the entry):
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index bcfc0734c06..0afa44a5491 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -72,7 +72,7 @@ from teams other than your own.
1. If your merge request includes adding a new UI/UX paradigm [^1], it must be
**approved by a [UX lead][team]**.
1. If your merge request includes a new dependency or a filesystem change, it must be
- **approved by a [Distribution team member][team]**. See how to work with the [Distribution team](https://about.gitlab.com/handbook/engineering/dev-backend/distribution/) for more details.
+ **approved by a [Distribution team member][team]**. See how to work with the [Distribution team](https://about.gitlab.com/handbook/engineering/development/enablement/distribution/#how-to-work-with-distribution) for more details.
#### Security requirements
diff --git a/doc/development/distributed_tracing.md b/doc/development/distributed_tracing.md
index 4776c8348d4..d2810fe89f0 100644
--- a/doc/development/distributed_tracing.md
+++ b/doc/development/distributed_tracing.md
@@ -27,7 +27,7 @@ no overhead at all.
To enable `GITLAB_TRACING`, a valid _"configuration-string"_ value should be set, with a URL-like
form:
-```console
+```sh
GITLAB_TRACING=opentracing://<driver>?<param_name>=<param_value>&<param_name_2>=<param_value_2>
```
@@ -90,7 +90,7 @@ documentation](https://www.jaegertracing.io/docs/1.9/getting-started/).
If you have Docker available, the easier approach to running the Jaeger all-in-one is through
Docker, using the following command:
-```console
+```sh
$ docker run \
--rm \
-e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
@@ -121,8 +121,8 @@ appropriate configuration string.
**TL;DR:** If you are running everything on the same host, use the following value:
-```console
-$ export GITLAB_TRACING="opentracing://jaeger?http_endpoint=http%3A%2F%2Flocalhost%3A14268%2Fapi%2Ftraces&sampler=const&sampler_param=1"
+```sh
+export GITLAB_TRACING="opentracing://jaeger?http_endpoint=http%3A%2F%2Flocalhost%3A14268%2Fapi%2Ftraces&sampler=const&sampler_param=1"
```
This configuration string uses the Jaeger driver `opentracing://jaeger` with the following options:
@@ -152,7 +152,7 @@ application.
When `GITLAB_TRACING` is configured properly, the application will log this on startup:
-```console
+```sh
13:41:53 gitlab-workhorse.1 | 2019/02/12 13:41:53 Tracing enabled
...
13:41:54 gitaly.1 | 2019/02/12 13:41:54 Tracing enabled
@@ -161,7 +161,7 @@ When `GITLAB_TRACING` is configured properly, the application will log this on s
If `GITLAB_TRACING` is not configured correctly, this will also be logged:
-```console
+```sh
13:43:45 gitaly.1 | 2019/02/12 13:43:45 skipping tracing configuration step: tracer: unable to load driver mytracer
```
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 4a50e90a26c..39b5e191a7b 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -262,7 +262,7 @@ table_display_block: true
## Punctuation
Check the general punctuation rules for the GitLab documentation on the table below.
-Check specific punctuation rules for [list items](#list-items) below.
+Check specific punctuation rules for [lists](#lists) below.
| Rule | Example |
| ---- | ------- |
@@ -274,37 +274,44 @@ Check specific punctuation rules for [list items](#list-items) below.
| Always add a space before and after dashes when using it in a sentence (for replacing a comma, for example). | _You should try this - or not._ |
| Always use lowercase after a colon. | _Related Issues: a way to create a relationship between issues._ |
-## List items
+## Lists
- Always start list items with a capital letter, unless they are parameters or commands
that are in backticks, or similar.
- Always leave a blank line before and after a list.
- Begin a line with spaces (not tabs) to denote a [nested subitem](#nesting-inside-a-list-item).
-- Only use ordered lists when their items describe a sequence of steps to follow:
- Do:
+### Ordered vs. unordered lists
- These are the steps to do something:
+Only use ordered lists when their items describe a sequence of steps to follow.
- 1. First, do step 1
- 1. Then, do step 2
- 1. Finally, do step 3
+Do:
+
+```md
+These are the steps to do something:
+
+1. First, do the first step.
+1. Then, do the next step.
+1. Finally, do the last step.
+```
- Don't:
+Don't:
- This is a list of different features:
+```md
+This is a list of available features:
- 1. Feature 1
- 1. Feature 2
- 1. Feature 3
+1. Feature 1
+1. Feature 2
+1. Feature 3
+```
-**Markup:**
+### Markup
- Use dashes (`-`) for unordered lists instead of asterisks (`*`).
-- Prefix `1.` to each item in an ordered list.
+- Prefix `1.` to every item in an ordered list.
When rendered, the list items will appear with sequential numbering automatically.
-**Punctuation:**
+### Punctuation
- Do not add commas (`,`) or semicolons (`;`) to the end of list items.
- Only add periods to the end of a list item if the item consists of a complete sentence.
@@ -343,7 +350,7 @@ Do:
- Let's say this is also a complete sentence.
- Not a complete sentence.
-Don't (third item should have a `.` to match the first and second items):
+Don't (vary use of periods; majority rules):
- Let's say this is a complete sentence.
- Let's say this is also a complete sentence.
diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md
index 557d3132d71..336ef4ab278 100644
--- a/doc/development/fe_guide/vuex.md
+++ b/doc/development/fe_guide/vuex.md
@@ -13,7 +13,7 @@ _Note:_ The action itself will not update the state, only a mutation should upda
## File structure
-When using Vuex at GitLab, separate this concerns into different files to improve readability:
+When using Vuex at GitLab, separate these concerns into different files to improve readability:
```
└── store
diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md
index 777d372ec60..b22a63621dc 100644
--- a/doc/development/instrumentation.md
+++ b/doc/development/instrumentation.md
@@ -81,9 +81,7 @@ If you're using Pry you can use the `$` command to display the source code of a
method (along with its source location), this is easier than running the above
Ruby code. In case of the above snippet you'd run the following:
-```
-$ Banzai::Renderer.render
-```
+- `$ Banzai::Renderer.render`
This will print out something along the lines of:
diff --git a/doc/development/performance.md b/doc/development/performance.md
index 14b3f8204d2..6e6c80b7a7c 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -123,7 +123,7 @@ Keeping that in mind, to create a profile, identify (or create) a spec that
exercises the troublesome code path, then run it using the `bin/rspec-stackprof`
helper, e.g.:
-```
+```sh
$ LIMIT=10 bin/rspec-stackprof spec/policies/project_policy_spec.rb
8/8 |====== 100 ======>| Time: 00:00:18
@@ -157,22 +157,22 @@ it calls, were being executed.
To create a graphical view of the call stack:
-```shell
-$ stackprof tmp/project_policy_spec.rb.dump --graphviz > project_policy_spec.dot
-$ dot -Tsvg project_policy_spec.dot > project_policy_spec.svg
+```sh
+stackprof tmp/project_policy_spec.rb.dump --graphviz > project_policy_spec.dot
+dot -Tsvg project_policy_spec.dot > project_policy_spec.svg
```
To load the profile in [kcachegrind](https://kcachegrind.github.io/):
-```
-$ stackprof tmp/project_policy_spec.dump --callgrind > project_policy_spec.callgrind
-$ kcachegrind project_policy_spec.callgrind # Linux
-$ qcachegrind project_policy_spec.callgrind # Mac
+```sh
+stackprof tmp/project_policy_spec.dump --callgrind > project_policy_spec.callgrind
+kcachegrind project_policy_spec.callgrind # Linux
+qcachegrind project_policy_spec.callgrind # Mac
```
It may be useful to zoom in on a specific method, e.g.:
-```
+```sh
$ stackprof tmp/project_policy_spec.rb.dump --method warm_asset_cache
TestEnv#warm_asset_cache (/Users/lupine/dev/gitlab.com/gitlab-org/gitlab-development-kit/gitlab/spec/support/test_env.rb:164)
samples: 0 self (0.0%) / 6288 total (36.9%)
@@ -225,9 +225,9 @@ may have changed over time.
To activate profiling in your local environment, run the following:
-```
-$ export RSPEC_PROFILING=yes
-$ rake rspec_profiling:install
+```sh
+export RSPEC_PROFILING=yes
+rake rspec_profiling:install
```
This creates an SQLite3 database in `tmp/rspec_profiling`, into which statistics
@@ -237,7 +237,7 @@ variable set.
Ad-hoc investigation of the collected results can be performed in an interactive
shell:
-```
+```sh
$ rake rspec_profiling:console
irb(main):001:0> results.count
=> 231
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 7dc89a3fcdb..91004bf177d 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -20,9 +20,18 @@ We have started to migrate frontend tests to the [Jest](https://jestjs.io) testi
Jest tests can be found in `/spec/frontend` and `/ee/spec/frontend` in EE.
-It is not yet a requirement to use Jest. You can view the
-[epic](https://gitlab.com/groups/gitlab-org/-/epics/873) of issues
-we need to solve before being able to use Jest for all our needs.
+### When should I use Jest over Karma?
+
+If you need to update an existing Karma test file (found in `spec/javascripts`), you do not
+need to migrate the whole spec to Jest. Simply updating the Karma spec to test your change
+is fine. It is probably more appropriate to migrate to Jest in a separate merge request.
+
+If you need to create a new test file, we strongly recommend creating one in Jest. This will
+help support our migration and we think you'll love using Jest.
+
+As always, please use discretion. Jest solves a lot of issues we experienced in Karma and
+provides a better developer experience, however there are potentially unexpected issues
+which could arise (especially with testing against browser specific features).
### Differences to Karma
diff --git a/doc/downgrade_ee_to_ce/README.md b/doc/downgrade_ee_to_ce/README.md
index a3f6f2b327c..0dc029a4cd1 100644
--- a/doc/downgrade_ee_to_ce/README.md
+++ b/doc/downgrade_ee_to_ce/README.md
@@ -47,14 +47,14 @@ to avoid getting this error, you need to remove all instances of the
**Omnibus Installation**
-```
-$ sudo gitlab-rails runner "Service.where(type: ['JenkinsService', 'JenkinsDeprecatedService', 'GithubService']).delete_all"
+```sh
+sudo gitlab-rails runner "Service.where(type: ['JenkinsService', 'JenkinsDeprecatedService', 'GithubService']).delete_all"
```
**Source Installation**
-```
-$ bundle exec rails runner "Service.where(type: ['JenkinsService', 'JenkinsDeprecatedService', 'GithubService']).delete_all" production
+```sh
+bundle exec rails runner "Service.where(type: ['JenkinsService', 'JenkinsDeprecatedService', 'GithubService']).delete_all" production
```
### Variables environment scopes
@@ -89,10 +89,10 @@ To downgrade a source installation, you need to replace the current remote of
your GitLab installation with the Community Edition's remote, fetch the latest
changes, and checkout the latest stable branch:
-```
-$ git remote set-url origin git@gitlab.com:gitlab-org/gitlab-ce.git
-$ git fetch --all
-$ git checkout 8-x-stable
+```sh
+git remote set-url origin git@gitlab.com:gitlab-org/gitlab-ce.git
+git fetch --all
+git checkout 8-x-stable
```
Remember to follow the correct [update guides](../update/README.md) to make
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index 358ba971049..ddf2b2fb738 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -613,6 +613,9 @@ To back up GitLab:
sudo gitlab-backup create
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
### Restoring GitLab from a backup
To restore GitLab, first review the [restore documentation](../../raketasks/backup_restore.md#restore),
@@ -631,6 +634,9 @@ released, you can update your GitLab instance:
sudo gitlab-backup create
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
1. Update the repositories and install GitLab:
```sh
diff --git a/doc/install/openshift_and_gitlab/index.md b/doc/install/openshift_and_gitlab/index.md
index fbbe2a34952..cfd0fd48c70 100644
--- a/doc/install/openshift_and_gitlab/index.md
+++ b/doc/install/openshift_and_gitlab/index.md
@@ -225,7 +225,7 @@ First, we will create a new project to host our application. You can do this
either by running the CLI client:
```bash
-$ oc new-project gitlab
+oc new-project gitlab
```
or by using the web interface:
diff --git a/doc/integration/github.md b/doc/integration/github.md
index f19b3109d15..23dd67f6891 100644
--- a/doc/integration/github.md
+++ b/doc/integration/github.md
@@ -158,7 +158,7 @@ For installation from source:
You will also need to disable Git SSL verification on the server hosting GitLab.
```
-$ git config --global http.sslVerify false
+git config --global http.sslVerify false
```
For the changes to take effect, [reconfigure GitLab] if you installed
diff --git a/doc/migrate_ci_to_ce/README.md b/doc/migrate_ci_to_ce/README.md
index 50e491f29a2..4a96001f2de 100644
--- a/doc/migrate_ci_to_ce/README.md
+++ b/doc/migrate_ci_to_ce/README.md
@@ -77,6 +77,9 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production SKIP=r
If this fails you need to fix it before upgrading to 8.0. Also see
<https://about.gitlab.com/get-help/>
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
### 2. Check source and target database types
Check what databases you use on your GitLab server and your CI server.
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 06048ad618f..c230bb413f2 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -80,6 +80,9 @@ Use this command if you've installed GitLab with the Omnibus package:
sudo gitlab-backup create
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
Use this if you've installed GitLab from source:
```sh
@@ -92,6 +95,9 @@ If you are running GitLab within a Docker container, you can run the backup from
docker exec -t <container name> gitlab-backup create
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
If you are using the [GitLab helm chart](https://gitlab.com/gitlab-org/charts/gitlab) on a
Kubernetes cluster, you can run the backup task using `backup-utility` script on
the GitLab task runner pod via `kubectl`. Refer to [backing up a GitLab installation](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/backup-restore/backup.md#backing-up-a-gitlab-installation) for more details:
@@ -202,6 +208,9 @@ To use the `copy` strategy instead of the default streaming strategy, specify
sudo gitlab-backup create STRATEGY=copy
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
### Backup filename
By default a backup file is created according to the specification in [the Backup timestamp](#backup-timestamp) section above. You can however override the `[TIMESTAMP]` part of the filename by setting the `BACKUP` environment variable. For example:
@@ -210,6 +219,9 @@ By default a backup file is created according to the specification in [the Backu
sudo gitlab-backup create BACKUP=dump
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
The resulting file will then be `dump_gitlab_backup.tar`. This is useful for systems that make use of rsync and incremental backups, and will result in considerably faster transfer speeds.
### Rsyncable
@@ -222,6 +234,9 @@ Note that the `--rsyncable` option in `gzip` is not guaranteed to be available o
sudo gitlab-backup create BACKUP=dump GZIP_RSYNCABLE=yes
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
### Excluding specific directories from the backup
You can choose what should be exempt from the backup up by adding the environment variable `SKIP`.
@@ -247,6 +262,9 @@ For Omnibus GitLab packages:
sudo gitlab-backup create SKIP=db,uploads
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
For installations from source:
```sh
@@ -452,6 +470,9 @@ sudo gitlab-backup create DIRECTORY=daily
sudo gitlab-backup create DIRECTORY=weekly
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
### Uploading to locally mounted shares
You may also send backups to a mounted share (`NFS` / `CIFS` / `SMB` / etc.) by
@@ -569,6 +590,9 @@ There, add the following line to schedule the backup for everyday at 2 AM:
0 2 * * * /opt/gitlab/bin/gitlab-backup create CRON=1
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+
You may also want to set a limited lifetime for backups to prevent regular
backups using all your disk space.
@@ -729,6 +753,14 @@ restore:
sudo gitlab-backup restore BACKUP=1493107454_2018_04_25_10.6.4-ce
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:restore`.
+
+CAUTION: **Warning:**
+`gitlab-rake gitlab:backup:restore` does not set the right file system permissions on your Registry directory.
+This is a [known issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/62759). On GitLab 12.2 or newer, you can
+use `gitlab-backup restore` to avoid this issue.
+
Next, restore `/etc/gitlab/gitlab-secrets.json` if necessary as mentioned above.
Reconfigure, restart and check GitLab:
@@ -763,6 +795,14 @@ For docker installations, the restore task can be run from host:
docker exec -it <name of container> gitlab-backup restore
```
+NOTE: **Note**
+For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:restore`.
+
+CAUTION: **Warning:**
+`gitlab-rake gitlab:backup:restore` does not set the right file system permissions on your Registry directory.
+This is a [known issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/62759). On GitLab 12.2 or newer, you can
+use `gitlab-backup restore` to avoid this issue.
+
The GitLab helm chart uses a different process, documented in
[restoring a GitLab helm chart installation](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/backup-restore/restore.md).
@@ -978,7 +1018,7 @@ sudo chown -R registry:registry /var/opt/gitlab/gitlab-rails/shared/registry/doc
NOTE: **Note:**
If you have changed the default filesystem location for the registry, you will
-want to run the chown against your custom location instead of
+want to run the `chown` against your custom location instead of
`/var/opt/gitlab/gitlab-rails/shared/registry/docker`.
[reconfigure GitLab]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure
@@ -990,6 +1030,7 @@ While running the backup, you may receive a gzip error:
```sh
sudo /opt/gitlab/bin/gitlab-backup create
+...
Dumping ...
...
gzip: stdout: Input/output error
@@ -999,5 +1040,5 @@ Backup failed
If this happens, check the following:
-1. Confirm there is sufficent diskspace for the gzip operation.
-1. If NFS is being used, check if the mount option `timeo` is set. The default is `600`, and changing this to smaller values have resulted in this error.
+1. Confirm there is sufficient disk space for the gzip operation.
+1. If NFS is being used, check if the mount option `timeout` is set. The default is `600`, and changing this to smaller values have resulted in this error.
diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md
index d93e7241fda..326f7e4b982 100644
--- a/doc/raketasks/import.md
+++ b/doc/raketasks/import.md
@@ -42,17 +42,17 @@ If you are using an installation from source, replace `/var/opt/gitlab/` with `/
#### Omnibus Installation
-```
-$ sudo gitlab-rake gitlab:import:repos['/var/opt/gitlab/git-data/repository-import-<date>']
+```sh
+sudo gitlab-rake gitlab:import:repos['/var/opt/gitlab/git-data/repository-import-<date>']
```
#### Installation from source
Before running this command you need to change the directory to where your GitLab installation is located:
-```
-$ cd /home/git/gitlab
-$ sudo -u git -H bundle exec rake gitlab:import:repos['/var/opt/gitlab/git-data/repository-import-<date>'] RAILS_ENV=production
+```sh
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:import:repos['/var/opt/gitlab/git-data/repository-import-<date>'] RAILS_ENV=production
```
#### Example output
diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md
index f6a1b6abdbf..b202dd7e9d2 100644
--- a/doc/update/mysql_to_postgresql.md
+++ b/doc/update/mysql_to_postgresql.md
@@ -13,7 +13,7 @@ NOTE: **Note:**
Support for MySQL was removed in GitLab 12.1. This procedure should be performed
**before** installing GitLab 12.1.
-[pgloader](https://pgloader.io/) 3.4.1+ is required.
+[pgloader](https://pgloader.io/) 3.4.1+ is required, confirm with `pgloader -V`.
You can install it directly from your distribution, for example in
Debian/Ubuntu:
@@ -125,6 +125,10 @@ new PostgreSQL one:
create no indexes, preserve index names, no foreign keys,
data only
+ SET MySQL PARAMETERS
+ net_read_timeout = '90',
+ net_write_timeout = '180'
+
ALTER SCHEMA 'gitlabhq_production' RENAME TO 'public'
;
@@ -222,6 +226,10 @@ new PostgreSQL one:
create no indexes, preserve index names, no foreign keys,
data only
+ SET MySQL PARAMETERS
+ net_read_timeout = '90',
+ net_write_timeout = '180'
+
ALTER SCHEMA 'gitlabhq_production' RENAME TO 'public'
;
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 89526c08e7e..166a71b6fbe 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -4,8 +4,11 @@ type: reference, howto
# Dependency Scanning **(ULTIMATE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5105)
-in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.7.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5105) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.7.
+
+Dependency Scanning helps to automatically find security vulnerabilities in your dependencies
+while you are developing and testing your applications, for example when your
+application is using an external (open source) library which is known to be vulnerable.
## Overview
@@ -18,7 +21,7 @@ in your existing `.gitlab-ci.yml` file or by implicitly using
that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
GitLab checks the Dependency Scanning report, compares the found vulnerabilities
-between the source and target branches, and shows the information right on the
+between the source and target branches, and shows the information on the
merge request.
![Dependency Scanning Widget](img/dependency_scanning.png)
@@ -32,12 +35,6 @@ The results are sorted by the severity of the vulnerability:
1. Unknown
1. Everything else
-## Use cases
-
-It helps to automatically find security vulnerabilities in your dependencies
-while you are developing and testing your applications. For example when your
-application is using an external (open source) library which is known to be vulnerable.
-
## Requirements
To run a Dependency Scanning job, you need GitLab Runner with the
@@ -146,7 +143,7 @@ Dependency Scanning can be [configured](#customizing-the-dependency-scanning-set
using environment variables.
| Environment variable | Description | Example usage |
-|-------------------------------- |-------------| |
+| --------------------------------------- | ----------- | ------------- |
| `DS_ANALYZER_IMAGES` | Comma separated list of custom images. The official default images are still enabled. Read more about [customizing analyzers](analyzers.md). | |
| `DS_ANALYZER_IMAGE_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). | |
| `DS_ANALYZER_IMAGE_TAG` | Override the Docker tag of the official default images. Read more about [customizing analyzers](analyzers.md). | |
@@ -162,10 +159,39 @@ using environment variables.
| `PIP_INDEX_URL` | Base URL of Python Package Index (default `https://pypi.org/simple`). | |
| `PIP_EXTRA_INDEX_URL` | Array of [extra URLs](https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-extra-index-url) of package indexes to use in addition to `PIP_INDEX_URL`. Comma separated. | |
+## Interacting with the vulnerabilities
+
+Once a vulnerability is found, you can interact with it. Read more on how to
+[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
+
+## Solutions for vulnerabilities (auto-remediation)
+
+Some vulnerabilities can be fixed by applying the solution that GitLab
+automatically generates.
+
+Read more about the [solutions for vulnerabilities](../index.md#solutions-for-vulnerabilities-auto-remediation).
+
+## Security Dashboard
+
+The Security Dashboard is a good place to get an overview of all the security
+vulnerabilities in your groups, projects and pipelines. Read more about the
+[Security Dashboard](../security_dashboard/index.md).
+
+## Vulnerabilities database update
+
+For more information about the vulnerabilities database update, check the
+[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
+
+## Dependency List
+
+An additional benefit of Dependency Scanning is the ability to view your
+project's dependencies and their known vulnerabilities. Read more about
+the [Dependency List](../dependency_list/index.md).
+
## Reports JSON format
CAUTION: **Caution:**
-The JSON report artifacts are not a public API of Dependency Scanning and their format may change in future.
+The JSON report artifacts are not a public API of Dependency Scanning and their format may change in the future.
The Dependency Scanning tool emits a JSON report file. Here is an example of the report structure with all important parts of
it highlighted:
@@ -315,28 +341,6 @@ the report JSON unless stated otherwise. Presence of optional fields depends on
| `remediations[].summary` | Overview of how the vulnerabilities have been fixed. |
| `remediations[].diff` | base64-encoded remediation code diff, compatible with [`git apply`](https://git-scm.com/docs/git-format-patch#_discussion). |
-## Security Dashboard
-
-The Security Dashboard is a good place to get an overview of all the security
-vulnerabilities in your groups, projects and pipelines. Read more about the
-[Security Dashboard](../security_dashboard/index.md).
-
-## Interacting with the vulnerabilities
-
-Once a vulnerability is found, you can interact with it. Read more on how to
-[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
-
-## Vulnerabilities database update
-
-For more information about the vulnerabilities database update, check the
-[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
-
-## Dependency List **(ULTIMATE)**
-
-An additional benefit of Dependency Scanning is the ability to view your
-project's dependencies and their known vulnerabilities. Read more about
-the [Dependency List](../dependency_list/index.md).
-
## Versioning and release process
Please check the [Release Process documentation](https://gitlab.com/gitlab-org/security-products/release/blob/master/docs/release_process.md).
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index 69529d7420b..f25d792cb90 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -71,8 +71,7 @@ entry, a detailed information will pop up with different possible options:
- [Create issue](#creating-an-issue-for-a-vulnerability): The new issue will
have the title and description pre-populated with the information from the
vulnerability report and will be created as [confidential](../project/issues/confidential_issues.md) by default.
-- [Solution](#solutions-for-vulnerabilities): For some vulnerabilities
- ([Dependency Scanning](dependency_scanning/index.md) and [Container Scanning](container_scanning/index.md))
+- [Solution](#solutions-for-vulnerabilities-auto-remediation): For some vulnerabilities,
a solution is provided for how to fix the vulnerability.
![Interacting with security reports](img/interactive_reports.png)
@@ -109,17 +108,16 @@ the vulnerability will now have an associated issue next to the name.
![Linked issue in the group security dashboard](img/issue.png)
-### Solutions for vulnerabilities
+### Solutions for vulnerabilities (auto-remediation)
-> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing) 11.7.
-
-CAUTION: **Warning:**
-Automatic Patch creation is only available for a subset of
-[Dependency Scanning](dependency_scanning/index.md). At the moment only Node.JS
-projects managed with yarn are supported.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5656) in [GitLab Ultimate](https://about.gitlab.com/pricing) 11.7.
Some vulnerabilities can be fixed by applying the solution that GitLab
-automatically generates.
+automatically generates. The following scanners are supported:
+
+- [Dependency Scanning](dependency_scanning/index.md):
+ Automatic Patch creation is only available for Node.JS projects managed with
+ `yarn`.
#### Manually applying the suggested patch
@@ -136,13 +134,12 @@ generated by GitLab. To apply the fix:
#### Creating a merge request from a vulnerability
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9224) in
-> [GitLab Ultimate](https://about.gitlab.com/pricing) 11.9.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9224) in [GitLab Ultimate](https://about.gitlab.com/pricing) 11.9.
In certain cases, GitLab will allow you to create a merge request that will
automatically remediate the vulnerability. Any vulnerability that has a
-[solution](#solutions-for-vulnerabilities) can have a merge request created to
-automatically solve the issue.
+[solution](#solutions-for-vulnerabilities-auto-remediation) can have a merge
+request created to automatically solve the issue.
If this action is available there will be a **Create merge request** button in the vulnerability modal.
Clicking on this button will create a merge request to apply the solution onto the source branch.
diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md
index 65b654d1553..e43b1ca6826 100644
--- a/doc/user/clusters/applications.md
+++ b/doc/user/clusters/applications.md
@@ -19,13 +19,11 @@ This namespace:
- Is created once.
- Has a non-configurable name.
-To see a list of available applications to install:
+To see a list of available applications to install. For a:
-1. For a:
- - [Project-level cluster](../project/clusters/index.md),
- navigate to your project's **Operations > Kubernetes**.
- - [Group-level cluster](../group/clusters/index.md),
- navigate to your group's **Kubernetes** page.
+- [Project-level cluster](../project/clusters/index.md), navigate to your project's
+ **Operations > Kubernetes**.
+- [Group-level cluster](../group/clusters/index.md), navigate to your group's **Kubernetes** page.
Install Helm first as it's used to install other applications.
@@ -61,8 +59,8 @@ can lead to confusion during deployments.
### Helm
-> - Available for project-level clusters since GitLab 10.2.
-> - Available for group-level clusters since GitLab 11.6.
+> - Introduced in GitLab 10.2 for project-level clusters.
+> - Introduced in GitLab 11.6 for group-level clusters.
[Helm](https://docs.helm.sh/) is a package manager for Kubernetes and is
required to install all the other applications. It is installed in its
@@ -71,8 +69,7 @@ environment.
### Cert-Manager
-> - Available for project-level clusters since GitLab 11.6.
-> - Available for group-level clusters since GitLab 11.6.
+> Introduced in GitLab 11.6 for project- and group-level clusters.
[Cert-Manager](https://docs.cert-manager.io/en/latest/) is a native
Kubernetes certificate management controller that helps with issuing
@@ -91,8 +88,8 @@ chart was used.
### GitLab Runner
-> - Available for project-level clusters since GitLab 10.6.
-> - Available for group-level clusters since GitLab 11.10.
+> - Introduced in GitLab 10.6 for project-level clusters.
+> - Introduced in GitLab 11.10 for group-level clusters.
[GitLab Runner](https://docs.gitlab.com/runner/) is the open source
project that is used to run your jobs and send the results back to
@@ -112,8 +109,8 @@ file.
### Ingress
-> - Available for project-level clusters since GitLab 10.2.
-> - Available for group-level clusters since GitLab 11.6.
+> - Introduced in GitLab 10.2 for project-level clusters.
+> - Introduced in GitLab 11.6 for group-level clusters.
[Ingress](https://kubernetes.github.io/ingress-nginx/) can provide load
balancing, SSL termination, and name-based virtual hosting. It acts as a
@@ -129,8 +126,8 @@ file.
### JupyterHub
-> - Available for project-level clusters since GitLab 11.0.
-> - Available for group-level clusters since GitLab 12.3.
+> - Introduced in GitLab 11.0 for project-level clusters.
+> - Introduced in GitLab 12.3 for group-level clusters.
[JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a
multi-user service for managing notebooks across a team. [Jupyter
@@ -163,7 +160,7 @@ file.
#### Jupyter Git Integration
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/28783) in GitLab 12 for project-level clusters.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/28783) in GitLab 12.0 for project-level clusters.
When installing JupyterHub onto your Kubernetes cluster, [JupyterLab's Git extension](https://github.com/jupyterlab/jupyterlab-git)
is automatically provisioned and configured using the authenticated user's:
@@ -190,8 +187,8 @@ You can clone repositories from the files tab in Jupyter:
### Knative
-> - Available for project-level clusters since GitLab 11.5.
-> - Available for group-level and instance-level clusters since GitLab 12.3.
+> - Introduced in GitLab 11.5 for project-level clusters.
+> - Introduced in GitLab 12.3 for group- and instance-level clusters.
[Knative](https://cloud.google.com/knative) provides a platform to
create, deploy, and manage serverless workloads from a Kubernetes
@@ -214,8 +211,8 @@ chart is used to install this application.
### Prometheus
-> - Available for project-level clusters since GitLab 10.4.
-> - Available for group-level clusters since GitLab 11.11.
+> - Introduced in GitLab 10.4 for project-level clusters.
+> - Introduced in GitLab 11.11 for group-level clusters.
[Prometheus](https://prometheus.io/docs/introduction/overview/) is an
open-source monitoring and alerting system useful to supervise your
@@ -255,8 +252,7 @@ chart plus the values set by
## Uninstalling applications
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/60665) in
-> GitLab 11.11.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/60665) in GitLab 11.11.
The applications below can be uninstalled.
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index edf2fedab3c..75a1ac8e9ff 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -1292,7 +1292,7 @@ Example:
Additionally, you can choose the alignment of text within columns by adding colons (`:`)
to the sides of the "dash" lines in the second row. This will affect every cell in the column.
-> Note that the headers are always right aligned [within GitLab itself itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#tables).
+> Note that the headers are always right aligned [within GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#tables).
```markdown
| Left Aligned | Centered | Right Aligned | Left Aligned | Centered | Right Aligned |
diff --git a/doc/user/profile/account/create_accounts.md b/doc/user/profile/account/create_accounts.md
new file mode 100644
index 00000000000..c0a887d0779
--- /dev/null
+++ b/doc/user/profile/account/create_accounts.md
@@ -0,0 +1,36 @@
+---
+type: reference
+---
+
+# Creating users **(CORE ONLY)**
+
+You can create users:
+
+- Manually through the sign in page or Admin Area.
+- Automatically through user authentication integrations.
+
+## Create users on sign in page
+
+If you have [sign-up enabled](../../admin_area/settings/sign_up_restrictions.md), users can create their own accounts using the **Register** tab on the sign in page.
+
+![Register Tab](img/register_tab.png)
+
+## Create users in admin area
+
+As an admin user, you can manually create users by:
+
+1. Navigating to **Admin Area > Overview > Users** (`/admin/users` page).
+1. Selecting the **New User** button.
+
+You can also [create users through the API](../../../api/users.md) as an admin.
+
+![Admin User Button](img/admin_user_button.png)
+
+![Admin User Form](img/admin_user_form.png)
+
+## Create users through integrations
+
+Users will be:
+
+- Automatically created upon first login with the [LDAP integration](../../../administration/auth/ldap.md).
+- Created when first logging in via an [OmniAuth provider](../../../integration/omniauth.md) if the `allow_single_sign_on` setting is present.
diff --git a/doc/user/profile/account/img/admin_user_button.png b/doc/user/profile/account/img/admin_user_button.png
new file mode 100644
index 00000000000..6be9c1e266a
--- /dev/null
+++ b/doc/user/profile/account/img/admin_user_button.png
Binary files differ
diff --git a/doc/user/profile/account/img/admin_user_form.png b/doc/user/profile/account/img/admin_user_form.png
new file mode 100644
index 00000000000..ede96373c73
--- /dev/null
+++ b/doc/user/profile/account/img/admin_user_form.png
Binary files differ
diff --git a/doc/user/profile/account/img/register_tab.png b/doc/user/profile/account/img/register_tab.png
new file mode 100644
index 00000000000..73faa3edd1c
--- /dev/null
+++ b/doc/user/profile/account/img/register_tab.png
Binary files differ
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index e5ccc8ee758..40b7294c3bb 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -8,6 +8,10 @@ Each GitLab account has a user profile, and settings. Your [profile](#user-profi
contains information about you, and your GitLab activity. Your [settings](#profile-settings)
allow you to customize some aspects of GitLab to suit yourself.
+## Creating users
+
+There are several ways to create users on GitLab. See the [creating users documentation](account/create_accounts.md) for more details.
+
## Signing in
There are several ways to sign into your GitLab account.
diff --git a/doc/user/project/canary_deployments.md b/doc/user/project/canary_deployments.md
index 5068d2757be..d4c8bf0d309 100644
--- a/doc/user/project/canary_deployments.md
+++ b/doc/user/project/canary_deployments.md
@@ -2,7 +2,7 @@
> [Introduced][ee-1659] in [GitLab Premium][eep] 9.1.
-A popular [Continuous Integration](https://en.wikipedia.org/wiki/Continuous_integration)
+A popular [Continuous Deployment](https://en.wikipedia.org/wiki/Continuous_deployment)
strategy, where a small portion of the fleet is updated to the new version of
your application.
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index cdb7f837158..dad53a600dc 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -6,14 +6,15 @@ your self-hosted GitLab instance.
## Overview
NOTE: **Note:**
-While these instructions will always work for users on GitLab.com, if you are an
-administrator of a self-hosted GitLab instance, you will need to enable the
-[GitHub integration][gh-import] in order for users to follow the preferred
-import method described on this page. If this is not enabled, users can alternatively import their
-GitHub repositories using a [personal access token](#using-a-github-token) from GitHub,
-but this method will not be able to associate all user activity (such as issues and pull requests)
-with matching GitLab users. As an administrator of a self-hosted GitLab instance, you can also use
-the [GitHub rake task](../../../administration/raketasks/github_import.md) to import projects from
+These instructions work for users on GitLab.com, but if you are an
+administrator of a self-hosted GitLab instance or if you are importing from GitHub Enterprise,
+you must enable [GitHub integration][gh-import]. GitHub integration is the only method for
+importing from GitHub Enterprise. If you are using GitLab.com, you can alternatively import
+GitHub repositories using a [personal access token](#using-a-github-token),
+but this method is not recommended because it cannot associate all user activity
+(such as issues and pull requests) with matching GitLab users.
+If you are an administrator of a self-hosted GitLab instance, you can also use the
+[GitHub rake task](../../../administration/raketasks/github_import.md) to import projects from
GitHub without the constraints of a Sidekiq worker.
The following aspects of a project are imported:
@@ -76,7 +77,7 @@ User-matching attempts occur in that order, and if a user is not identified eith
the user account that is performing the import.
NOTE: **Note:**
-If you are using a self-hosted GitLab instance, this process requires that you have configured the
+If you are using a self-hosted GitLab instance or if you are importing from GitHub Enterprise, this process requires that you have configured
[GitHub integration][gh-import].
1. From the top navigation bar, click **+** and select **New project**.
@@ -88,9 +89,13 @@ If you are using a self-hosted GitLab instance, this process requires that you h
### Using a GitHub token
NOTE: **Note:**
-For a proper author/assignee mapping for issues and pull requests, the [GitHub integration method (above)](#using-the-github-integration)
-should be used instead of the personal access token. If you are using GitLab.com or a self-hosted GitLab instance with the GitHub
-integration enabled, that should be the preferred method to import your repositories. Read more in the [How it works](#how-it-works) section.
+Using a personal access token to import projects is not recommended. If you are a GitLab.com user,
+you can use a personal access token to import your project from GitHub, but this method cannot
+associate all user activity (such as issues and pull requests) with matching GitLab users.
+If you are an administrator of a self-hosted GitLab instance or if you are importing from
+GitHub Enterprise, you cannot use a personal access token.
+The [GitHub integration method (above)](#using-the-github-integration) is recommended for all users.
+Read more in the [How it works](#how-it-works) section.
If you are not using the GitHub integration, you can still perform an authorization with GitHub to grant GitLab access your repositories:
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index aa58e971cc3..c19e96b4482 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -630,10 +630,7 @@ troubleshooting steps.
### Merge request cannot retrieve the pipeline status
-This can occur for one of two reasons:
-
-- Sidekiq doesn't pick up the changes fast enough
-- Because of the bug described in [#41545](https://gitlab.com/gitlab-org/gitlab-ce/issues/41545)
+This can occur if Sidekiq doesn't pick up the changes fast enough.
#### Sidekiq
diff --git a/doc/user/project/merge_requests/merge_request_approvals.md b/doc/user/project/merge_requests/merge_request_approvals.md
index ca9ddd91e0d..a18c2d3a21f 100644
--- a/doc/user/project/merge_requests/merge_request_approvals.md
+++ b/doc/user/project/merge_requests/merge_request_approvals.md
@@ -184,6 +184,10 @@ the merge request. To enable this feature:
When this feature is enabled, all merge requests will need approval
from one code owner per matched rule before it can be merged.
+NOTE: **Note:** Only the `CODEOWNERS` file on the default branch is evaluated for
+Merge Request approvals. If `CODEOWNERS` is changed on a non-default branch, those
+changes will not affect approvals until merged to the default branch.
+
## Overriding the merge request approvals default settings
> Introduced in GitLab Enterprise Edition 9.4.
@@ -196,7 +200,7 @@ If approvals are [set at the project level](#editing-approvals), the
default configuration (number of required approvals and approvers) can be
overridden for each merge request in that project.
-One possible scenario would be to to assign a group of approvers at the project
+One possible scenario would be to assign a group of approvers at the project
level and change them later when creating or editing the merge request.
First, you have to enable this option in the project's settings:
diff --git a/doc/user/project/pages/getting_started_part_four.md b/doc/user/project/pages/getting_started_part_four.md
index d844d4222b1..80fa64b162d 100644
--- a/doc/user/project/pages/getting_started_part_four.md
+++ b/doc/user/project/pages/getting_started_part_four.md
@@ -53,9 +53,9 @@ write in the `.gitlab-ci.yml` the script you want to run so
GitLab Runner will do it for you. It looks more complicated than it
is. What you need to tell the Runner:
-```
-$ gem install jekyll
-$ jekyll build
+```sh
+gem install jekyll
+jekyll build
```
### Script
diff --git a/doc/workflow/lfs/lfs_administration.md b/doc/workflow/lfs/lfs_administration.md
index 7e880b3009d..8db62997b51 100644
--- a/doc/workflow/lfs/lfs_administration.md
+++ b/doc/workflow/lfs/lfs_administration.md
@@ -134,13 +134,13 @@ There are two ways to manually do the same thing as automatic uploading (describ
**Option 1: rake task**
-```
-$ rake gitlab:lfs:migrate
+```sh
+rake gitlab:lfs:migrate
```
**Option 2: rails console**
-```
+```sh
$ sudo gitlab-rails console # Login to rails console
> # Upload LFS files manually
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index c9b3483acaf..312c8d5b548 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1312,6 +1312,10 @@ module API
options[:project].releases.find_by(tag: repo_tag.name)
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ expose :protected do |repo_tag, options|
+ ::ProtectedTag.protected?(options[:project], repo_tag.name)
+ end
end
class Runner < Grape::Entity
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 5755f4b8d74..e61b25721fb 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -5,10 +5,10 @@ module API
include Gitlab::Utils
include Helpers::Pagination
- SUDO_HEADER = "HTTP_SUDO".freeze
- GITLAB_SHARED_SECRET_HEADER = "Gitlab-Shared-Secret".freeze
+ SUDO_HEADER = "HTTP_SUDO"
+ GITLAB_SHARED_SECRET_HEADER = "Gitlab-Shared-Secret"
SUDO_PARAM = :sudo
- API_USER_ENV = 'gitlab.api.user'.freeze
+ API_USER_ENV = 'gitlab.api.user'
def declared_params(options = {})
options = { include_parent_namespaces: false }.merge(options)
diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb
index 5b87eccf860..41ee34a8fdf 100644
--- a/lib/api/helpers/runner.rb
+++ b/lib/api/helpers/runner.rb
@@ -3,7 +3,7 @@
module API
module Helpers
module Runner
- JOB_TOKEN_HEADER = 'HTTP_JOB_TOKEN'.freeze
+ JOB_TOKEN_HEADER = 'HTTP_JOB_TOKEN'
JOB_TOKEN_PARAM = :token
def runner_registration_token_valid?
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index dd27ebab83d..acf03051a5b 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -50,10 +50,8 @@ module API
optional :default_snippet_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default snippet visibility'
optional :disabled_oauth_sign_in_sources, type: Array[String], desc: 'Disable certain OAuth sign-in sources'
optional :domain_blacklist_enabled, type: Boolean, desc: 'Enable domain blacklist for sign ups'
- given domain_blacklist_enabled: ->(val) { val } do
- requires :domain_blacklist, type: String, desc: 'Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com'
- end
- optional :domain_whitelist, type: String, desc: 'ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com'
+ optional :domain_blacklist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com'
+ optional :domain_whitelist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com'
optional :email_author_in_body, type: Boolean, desc: 'Some email servers do not support overriding the email sender name. Enable this option to include the name of the author of the issue, merge request or comment in the email body instead.'
optional :enabled_git_access_protocol, type: String, values: %w[ssh http nil], desc: 'Allow only the selected protocols to be used for Git access.'
optional :gitaly_timeout_default, type: Integer, desc: 'Default Gitaly timeout, in seconds. Set to 0 to disable timeouts.'
@@ -74,7 +72,7 @@ module API
requires :housekeeping_incremental_repack_period, type: Integer, desc: "Number of Git pushes after which an incremental 'git repack' is run."
end
optional :html_emails_enabled, type: Boolean, desc: 'By default GitLab sends emails in HTML and plain text formats so mail clients can choose what format to use. Disable this option if you only want to send emails in plain text format.'
- optional :import_sources, type: Array[String], values: %w[github bitbucket gitlab google_code fogbugz git gitlab_project manifest],
+ optional :import_sources, type: Array[String], values: %w[github bitbucket bitbucket_server gitlab google_code fogbugz git gitlab_project gitea manifest phabricator],
desc: 'Enabled sources for code import during project creation. OmniAuth must be configured for GitHub, Bitbucket, and GitLab.com'
optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts"
optional :max_attachment_size, type: Integer, desc: 'Maximum attachment size in MB'
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index aeaf61cda39..c0390959269 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -4,7 +4,7 @@ module Backup
class Manager
ARCHIVES_TO_BACKUP = %w[uploads builds artifacts pages lfs registry].freeze
FOLDERS_TO_BACKUP = %w[repositories db].freeze
- FILE_NAME_SUFFIX = '_gitlab_backup.tar'.freeze
+ FILE_NAME_SUFFIX = '_gitlab_backup.tar'
attr_reader :progress
diff --git a/lib/banzai/filter/color_filter.rb b/lib/banzai/filter/color_filter.rb
index 6d9bdb9cbd3..0aca7441638 100644
--- a/lib/banzai/filter/color_filter.rb
+++ b/lib/banzai/filter/color_filter.rb
@@ -5,7 +5,7 @@ module Banzai
# HTML filter that renders `color` followed by a color "chip".
#
class ColorFilter < HTML::Pipeline::Filter
- COLOR_CHIP_CLASS = 'gfm-color_chip'.freeze
+ COLOR_CHIP_CLASS = 'gfm-color_chip'
def call
doc.css('code').each do |node|
diff --git a/lib/banzai/filter/external_link_filter.rb b/lib/banzai/filter/external_link_filter.rb
index fb721fe12b1..67019454e44 100644
--- a/lib/banzai/filter/external_link_filter.rb
+++ b/lib/banzai/filter/external_link_filter.rb
@@ -5,8 +5,8 @@ module Banzai
# HTML Filter to modify the attributes of external links
class ExternalLinkFilter < HTML::Pipeline::Filter
SCHEMES = ['http', 'https', nil].freeze
- RTLO = "\u202E".freeze
- ENCODED_RTLO = '%E2%80%AE'.freeze
+ RTLO = "\u202E"
+ ENCODED_RTLO = '%E2%80%AE'
def call
links.each do |node|
diff --git a/lib/banzai/filter/footnote_filter.rb b/lib/banzai/filter/footnote_filter.rb
index de133774dfa..5474242e03c 100644
--- a/lib/banzai/filter/footnote_filter.rb
+++ b/lib/banzai/filter/footnote_filter.rb
@@ -17,8 +17,8 @@ module Banzai
#
class FootnoteFilter < HTML::Pipeline::Filter
INTEGER_PATTERN = /\A\d+\z/.freeze
- FOOTNOTE_ID_PREFIX = 'fn'.freeze
- FOOTNOTE_LINK_ID_PREFIX = 'fnref'.freeze
+ FOOTNOTE_ID_PREFIX = 'fn'
+ FOOTNOTE_LINK_ID_PREFIX = 'fnref'
FOOTNOTE_LI_REFERENCE_PATTERN = /\A#{FOOTNOTE_ID_PREFIX}\d+\z/.freeze
FOOTNOTE_LINK_REFERENCE_PATTERN = /\A#{FOOTNOTE_LINK_ID_PREFIX}\d+\z/.freeze
FOOTNOTE_START_NUMBER = 1
diff --git a/lib/banzai/filter/math_filter.rb b/lib/banzai/filter/math_filter.rb
index 8dd5a8979c8..c915f0ee35b 100644
--- a/lib/banzai/filter/math_filter.rb
+++ b/lib/banzai/filter/math_filter.rb
@@ -11,14 +11,14 @@ module Banzai
#
class MathFilter < HTML::Pipeline::Filter
# Attribute indicating inline or display math.
- STYLE_ATTRIBUTE = 'data-math-style'.freeze
+ STYLE_ATTRIBUTE = 'data-math-style'
# Class used for tagging elements that should be rendered
- TAG_CLASS = 'js-render-math'.freeze
+ TAG_CLASS = 'js-render-math'
- INLINE_CLASSES = "code math #{TAG_CLASS}".freeze
+ INLINE_CLASSES = "code math #{TAG_CLASS}"
- DOLLAR_SIGN = '$'.freeze
+ DOLLAR_SIGN = '$'
def call
doc.css('code').each do |code|
diff --git a/lib/banzai/filter/suggestion_filter.rb b/lib/banzai/filter/suggestion_filter.rb
index 3d40abfc540..ae093580001 100644
--- a/lib/banzai/filter/suggestion_filter.rb
+++ b/lib/banzai/filter/suggestion_filter.rb
@@ -5,7 +5,7 @@ module Banzai
module Filter
class SuggestionFilter < HTML::Pipeline::Filter
# Class used for tagging elements that should be rendered
- TAG_CLASS = 'js-render-suggestion'.freeze
+ TAG_CLASS = 'js-render-suggestion'
def call
return doc unless suggestions_filter_enabled?
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index 9b66759a5fb..c1a5f33c225 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -10,8 +10,8 @@ module Banzai
class SyntaxHighlightFilter < HTML::Pipeline::Filter
include OutputSafety
- PARAMS_DELIMITER = ':'.freeze
- LANG_PARAMS_ATTR = 'data-lang-params'.freeze
+ PARAMS_DELIMITER = ':'
+ LANG_PARAMS_ATTR = 'data-lang-params'
def call
doc.search('pre:not([data-math-style]) > code').each do |node|
diff --git a/lib/banzai/issuable_extractor.rb b/lib/banzai/issuable_extractor.rb
index 341dbb74fe0..31bb4f2e01c 100644
--- a/lib/banzai/issuable_extractor.rb
+++ b/lib/banzai/issuable_extractor.rb
@@ -11,8 +11,8 @@ module Banzai
class IssuableExtractor
attr_reader :context
- ISSUE_REFERENCE_TYPE = '@data-reference-type="issue"'.freeze
- MERGE_REQUEST_REFERENCE_TYPE = '@data-reference-type="merge_request"'.freeze
+ ISSUE_REFERENCE_TYPE = '@data-reference-type="issue"'
+ MERGE_REQUEST_REFERENCE_TYPE = '@data-reference-type="merge_request"'
# context - An instance of Banzai::RenderContext.
def initialize(context)
diff --git a/lib/bitbucket/connection.rb b/lib/bitbucket/connection.rb
index 0041634f9e3..9937236fc44 100644
--- a/lib/bitbucket/connection.rb
+++ b/lib/bitbucket/connection.rb
@@ -2,8 +2,8 @@
module Bitbucket
class Connection
- DEFAULT_API_VERSION = '2.0'.freeze
- DEFAULT_BASE_URI = 'https://api.bitbucket.org/'.freeze
+ DEFAULT_API_VERSION = '2.0'
+ DEFAULT_BASE_URI = 'https://api.bitbucket.org/'
DEFAULT_QUERY = {}.freeze
attr_reader :expires_at, :expires_in, :refresh_token, :token
diff --git a/lib/gitlab.rb b/lib/gitlab.rb
index e8b938e46b1..582541c0679 100644
--- a/lib/gitlab.rb
+++ b/lib/gitlab.rb
@@ -29,13 +29,13 @@ module Gitlab
if result.status.success?
result.stdout.chomp.freeze
else
- "Unknown".freeze
+ "Unknown"
end
end
end
end
- COM_URL = 'https://gitlab.com'.freeze
+ COM_URL = 'https://gitlab.com'
APP_DIRS_PATTERN = %r{^/?(app|config|ee|lib|spec|\(\w*\))}.freeze
SUBDOMAIN_REGEX = %r{\Ahttps://[a-z0-9]+\.gitlab\.com\z}.freeze
VERSION = File.read(root.join("VERSION")).strip.freeze
diff --git a/lib/gitlab/import_export/attributes_finder.rb b/lib/gitlab/import_export/attributes_finder.rb
index 13883ca7f3d..28d48ce6dfe 100644
--- a/lib/gitlab/import_export/attributes_finder.rb
+++ b/lib/gitlab/import_export/attributes_finder.rb
@@ -8,6 +8,7 @@ module Gitlab
@included_attributes = config[:included_attributes] || {}
@excluded_attributes = config[:excluded_attributes] || {}
@methods = config[:methods] || {}
+ @preloads = config[:preloads] || {}
end
def find_root(model_key)
@@ -29,10 +30,26 @@ module Gitlab
only: @included_attributes[model_key],
except: @excluded_attributes[model_key],
methods: @methods[model_key],
- include: resolve_model_tree(model_tree)
+ include: resolve_model_tree(model_tree),
+ preload: resolve_preloads(model_key, model_tree)
}.compact
end
+ def resolve_preloads(model_key, model_tree)
+ model_tree
+ .map { |submodel_key, submodel_tree| resolve_preload(model_key, submodel_key, submodel_tree) }
+ .compact
+ .to_h
+ .deep_merge(@preloads[model_key].to_h)
+ .presence
+ end
+
+ def resolve_preload(parent_model_key, model_key, model_tree)
+ return if @methods[parent_model_key]&.include?(model_key)
+
+ [model_key, resolve_preloads(model_key, model_tree)]
+ end
+
def resolve_model_tree(model_tree)
return unless model_tree
diff --git a/lib/gitlab/import_export/fast_hash_serializer.rb b/lib/gitlab/import_export/fast_hash_serializer.rb
new file mode 100644
index 00000000000..a6ab4f3a3d9
--- /dev/null
+++ b/lib/gitlab/import_export/fast_hash_serializer.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+# ActiveModel::Serialization (https://github.com/rails/rails/blob/v5.0.7/activemodel/lib/active_model/serialization.rb#L184)
+# is simple in that it recursively calls `as_json` on each object to
+# serialize everything. However, for a model like a Project, this can
+# generate a query for every single association, which can add up to tens
+# of thousands of queries and lead to memory bloat.
+#
+# To improve this, we can do several things:
+
+# 1. Use the option tree in http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html
+# to generate the necessary preload clauses.
+#
+# 2. We observe that a single project has many issues, merge requests,
+# etc. Instead of serializing everything at once, which could lead to
+# database timeouts and high memory usage, we take each top-level
+# association and serialize the data in batches.
+#
+# For example, we serialize the first 100 issues and preload all of
+# their associated events, notes, etc. before moving onto the next
+# batch. When we're done, we serialize merge requests in the same way.
+# We repeat this pattern for the remaining associations specified in
+# import_export.yml.
+module Gitlab
+ module ImportExport
+ class FastHashSerializer
+ attr_reader :subject, :tree
+
+ BATCH_SIZE = 100
+
+ def initialize(subject, tree, batch_size: BATCH_SIZE)
+ @subject = subject
+ @batch_size = batch_size
+ @tree = tree
+ end
+
+ # Serializes the subject into a Hash for the given option tree
+ # (e.g. Project#as_json)
+ def execute
+ simple_serialize.merge(serialize_includes)
+ end
+
+ private
+
+ def simple_serialize
+ subject.as_json(
+ tree.merge(include: nil, preloads: nil))
+ end
+
+ def serialize_includes
+ return {} unless includes
+
+ includes
+ .map(&method(:serialize_include_definition))
+ .compact
+ .to_h
+ end
+
+ # definition:
+ # { labels: { includes: ... } }
+ def serialize_include_definition(definition)
+ raise ArgumentError, 'definition needs to be Hash' unless definition.is_a?(Hash)
+ raise ArgumentError, 'definition needs to have exactly one Hash element' unless definition.one?
+
+ key = definition.first.first
+ options = definition.first.second
+
+ record = subject.public_send(key) # rubocop: disable GitlabSecurity/PublicSend
+ return unless record
+
+ serialized_record = serialize_record(key, record, options)
+ return unless serialized_record
+
+ # `#as_json` always returns keys as `strings`
+ [key.to_s, serialized_record]
+ end
+
+ def serialize_record(key, record, options)
+ unless record.respond_to?(:as_json)
+ raise "Invalid type of #{key} is #{record.class}"
+ end
+
+ # no has-many relation
+ unless record.is_a?(ActiveRecord::Relation)
+ return record.as_json(options)
+ end
+
+ # has-many relation
+ data = []
+
+ record.in_batches(of: @batch_size) do |batch| # rubocop:disable Cop/InBatches
+ batch = batch.preload(preloads[key]) if preloads&.key?(key)
+ data += batch.as_json(options)
+ end
+
+ data
+ end
+
+ def includes
+ tree[:include]
+ end
+
+ def preloads
+ tree[:preload]
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index 06c94beead8..511b702553e 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -231,6 +231,16 @@ methods:
ci_pipelines:
- :notes
+preloads:
+ statuses:
+ # TODO: We cannot preload tags, as they are not part of `GenericCommitStatus`
+ # tags: # needed by tag_list
+ project: # deprecated: needed by coverage_regex of Ci::Build
+ merge_requests:
+ source_project: # needed by source_branch_sha and diff_head_sha
+ target_project: # needed by target_branch_sha
+ assignees: # needed by assigne_id that is implemented by DeprecatedAssignee
+
# EE specific relationships and settings to include. All of this will be merged
# into the previous structures if EE is used.
ee:
diff --git a/lib/gitlab/import_export/project_tree_saver.rb b/lib/gitlab/import_export/project_tree_saver.rb
index f1b3db6b208..f75f69b2c75 100644
--- a/lib/gitlab/import_export/project_tree_saver.rb
+++ b/lib/gitlab/import_export/project_tree_saver.rb
@@ -41,7 +41,13 @@ module Gitlab
end
def serialize_project_tree
- @project.as_json(reader.project_tree)
+ if Feature.enabled?(:export_fast_serialize, default_enabled: true)
+ Gitlab::ImportExport::FastHashSerializer
+ .new(@project, reader.project_tree)
+ .execute
+ else
+ @project.as_json(reader.project_tree)
+ end
end
def reader
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index ce4c1611687..93e172299b9 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -2,7 +2,8 @@
module Gitlab
class SearchResults
- COUNT_LIMIT = 1001
+ COUNT_LIMIT = 101
+ COUNT_LIMIT_MESSAGE = "#{COUNT_LIMIT - 1}+"
attr_reader :current_user, :query, :per_page
@@ -60,7 +61,7 @@ module Gitlab
def formatted_limited_count(count)
if count >= COUNT_LIMIT
- "#{COUNT_LIMIT - 1}+"
+ COUNT_LIMIT_MESSAGE
else
count.to_s
end
diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb
index b5f99ea012b..9f01a3f97ce 100644
--- a/lib/google_api/cloud_platform/client.rb
+++ b/lib/google_api/cloud_platform/client.rb
@@ -8,9 +8,9 @@ require 'google/apis/cloudresourcemanager_v1'
module GoogleApi
module CloudPlatform
class Client < GoogleApi::Auth
- SCOPE = 'https://www.googleapis.com/auth/cloud-platform'.freeze
+ SCOPE = 'https://www.googleapis.com/auth/cloud-platform'
LEAST_TOKEN_LIFE_TIME = 10.minutes
- CLUSTER_MASTER_AUTH_USERNAME = 'admin'.freeze
+ CLUSTER_MASTER_AUTH_USERNAME = 'admin'
class << self
def session_key_for_token
diff --git a/lib/quality/test_level.rb b/lib/quality/test_level.rb
index 60d79b52680..a65657dadd0 100644
--- a/lib/quality/test_level.rb
+++ b/lib/quality/test_level.rb
@@ -53,7 +53,7 @@ module Quality
end
def pattern(level)
- @patterns[level] ||= "#{prefix}spec/{#{TEST_LEVEL_FOLDERS.fetch(level).join(',')}}{,/**/}*_spec.rb".freeze
+ @patterns[level] ||= "#{prefix}spec/{#{TEST_LEVEL_FOLDERS.fetch(level).join(',')}}{,/**/}*_spec.rb"
end
def regexp(level)
diff --git a/lib/system_check/app/init_script_up_to_date_check.rb b/lib/system_check/app/init_script_up_to_date_check.rb
index 569c41df6e4..7e2e168af8b 100644
--- a/lib/system_check/app/init_script_up_to_date_check.rb
+++ b/lib/system_check/app/init_script_up_to_date_check.rb
@@ -3,7 +3,7 @@
module SystemCheck
module App
class InitScriptUpToDateCheck < SystemCheck::BaseCheck
- SCRIPT_PATH = '/etc/init.d/gitlab'.freeze
+ SCRIPT_PATH = '/etc/init.d/gitlab'
set_name 'Init script up-to-date?'
set_skip_reason 'skipped (omnibus-gitlab has no init script)'
diff --git a/lib/system_check/app/redis_version_check.rb b/lib/system_check/app/redis_version_check.rb
index 890f8b44d13..da695cc9272 100644
--- a/lib/system_check/app/redis_version_check.rb
+++ b/lib/system_check/app/redis_version_check.rb
@@ -3,7 +3,7 @@
module SystemCheck
module App
class RedisVersionCheck < SystemCheck::BaseCheck
- MIN_REDIS_VERSION = '2.8.0'.freeze
+ MIN_REDIS_VERSION = '2.8.0'
set_name "Redis version >= #{MIN_REDIS_VERSION}?"
def check?
diff --git a/lib/tasks/gitlab/graphql.rake b/lib/tasks/gitlab/graphql.rake
index c53d55ceea2..fd8df015903 100644
--- a/lib/tasks/gitlab/graphql.rake
+++ b/lib/tasks/gitlab/graphql.rake
@@ -3,8 +3,8 @@
return if Rails.env.production?
namespace :gitlab do
- OUTPUT_DIR = Rails.root.join("doc/api/graphql/reference").freeze
- TEMPLATES_DIR = 'lib/gitlab/graphql/docs/templates/'.freeze
+ OUTPUT_DIR = Rails.root.join("doc/api/graphql/reference")
+ TEMPLATES_DIR = 'lib/gitlab/graphql/docs/templates/'
namespace :graphql do
desc 'GitLab | Generate GraphQL docs'
diff --git a/lib/tasks/gitlab/uploads/legacy.rake b/lib/tasks/gitlab/uploads/legacy.rake
index 18fb8afe455..2eeb694d341 100644
--- a/lib/tasks/gitlab/uploads/legacy.rake
+++ b/lib/tasks/gitlab/uploads/legacy.rake
@@ -11,7 +11,7 @@ namespace :gitlab do
include ::EachBatch
end
- migration = 'LegacyUploadsMigrator'.freeze
+ migration = 'LegacyUploadsMigrator'
batch_size = 5000
delay_interval = 5.minutes.to_i
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a77d70a5700..32deab7dd68 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2530,6 +2530,9 @@ msgstr ""
msgid "ClusterIntegration|Alternatively"
msgstr ""
+msgid "ClusterIntegration|Amazon EKS"
+msgstr ""
+
msgid "ClusterIntegration|An error occurred when trying to contact the Google Cloud API. Please try again later."
msgstr ""
@@ -2608,6 +2611,9 @@ msgstr ""
msgid "ClusterIntegration|Create Kubernetes cluster"
msgstr ""
+msgid "ClusterIntegration|Create cluster on"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -2659,6 +2665,9 @@ msgstr ""
msgid "ClusterIntegration|Google Cloud Platform project"
msgstr ""
+msgid "ClusterIntegration|Google GKE"
+msgstr ""
+
msgid "ClusterIntegration|Google Kubernetes Engine"
msgstr ""
@@ -2989,9 +2998,6 @@ msgstr ""
msgid "ClusterIntegration|pricing"
msgstr ""
-msgid "ClusterIntegration|properly configured"
-msgstr ""
-
msgid "ClusterIntegration|sign up"
msgstr ""
@@ -5518,7 +5524,7 @@ msgstr ""
msgid "Google Takeout"
msgstr ""
-msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
+msgid "Google authentication is not %{link_start}property configured%{link_end}. Ask your GitLab administrator if you want to use this service."
msgstr ""
msgid "Got it"
@@ -10565,6 +10571,9 @@ msgstr ""
msgid "Sign in via 2FA code"
msgstr ""
+msgid "Sign in with Google"
+msgstr ""
+
msgid "Sign out"
msgstr ""
@@ -12299,6 +12308,9 @@ msgstr ""
msgid "Toggle backtrace"
msgstr ""
+msgid "Toggle collapse"
+msgstr ""
+
msgid "Toggle comments for this file"
msgstr ""
@@ -14180,7 +14192,7 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "or"
+msgid "or %{link_start}create a new Google account%{link_end}"
msgstr ""
msgid "out of %d total test"
diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb
index 52929ece9ed..e5e26b1864b 100644
--- a/qa/qa/page/project/issue/show.rb
+++ b/qa/qa/page/project/issue/show.rb
@@ -35,12 +35,17 @@ module QA
element :labels_block
element :edit_link_labels
element :dropdown_menu_labels
+ element :milestone_link
end
view 'app/views/shared/issuable/_close_reopen_button.html.haml' do
element :reopen_issue_button
end
+ def click_milestone_link
+ click_element(:milestone_link)
+ end
+
# Adds a comment to an issue
# attachment option should be an absolute path
def comment(text, attachment: nil, filter: :all_activities)
diff --git a/qa/qa/page/project/milestone/index.rb b/qa/qa/page/project/milestone/index.rb
index 6895c44f72f..8ad7689ce70 100644
--- a/qa/qa/page/project/milestone/index.rb
+++ b/qa/qa/page/project/milestone/index.rb
@@ -17,3 +17,5 @@ module QA
end
end
end
+
+QA::Page::Project::Milestone::Index.prepend_if_ee('QA::EE::Page::Project::Milestone::Index')
diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb
index 16ab59352f3..8539eaeb337 100644
--- a/qa/qa/resource/issue.rb
+++ b/qa/qa/resource/issue.rb
@@ -3,7 +3,7 @@
module QA
module Resource
class Issue < Base
- attr_writer :description, :milestone
+ attr_writer :description, :milestone, :weight
attribute :project do
Project.fabricate! do |resource|
@@ -46,6 +46,7 @@ module QA
title: title
}.tap do |hash|
hash[:milestone_id] = @milestone.id if @milestone
+ hash[:weight] = @weight if @weight
end
end
end
diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb
index e5501535875..afc059d7561 100644
--- a/spec/controllers/admin/clusters_controller_spec.rb
+++ b/spec/controllers/admin/clusters_controller_spec.rb
@@ -73,8 +73,8 @@ describe Admin::ClustersController do
end
describe 'GET #new' do
- def get_new
- get :new
+ def get_new(provider: 'gke')
+ get :new, params: { provider: provider }
end
describe 'functionality for new cluster' do
@@ -85,6 +85,7 @@ describe Admin::ClustersController do
end
before do
+ stub_feature_flags(create_eks_clusters: false)
allow(SecureRandom).to receive(:hex).and_return(key)
end
@@ -94,6 +95,20 @@ describe Admin::ClustersController do
expect(assigns(:authorize_url)).to include(key)
expect(session[session_key_for_redirect_uri]).to eq(new_admin_cluster_path)
end
+
+ context 'when create_eks_clusters feature flag is enabled' do
+ before do
+ stub_feature_flags(create_eks_clusters: true)
+ end
+
+ context 'when selected provider is gke and no valid gcp token exists' do
+ it 'redirects to gcp authorize_url' do
+ get_new
+
+ expect(response).to redirect_to(assigns(:authorize_url))
+ end
+ end
+ end
end
context 'when omniauth has not configured' do
diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb
index 09677b42887..5a3ba51d4df 100644
--- a/spec/controllers/groups/clusters_controller_spec.rb
+++ b/spec/controllers/groups/clusters_controller_spec.rb
@@ -85,8 +85,8 @@ describe Groups::ClustersController do
end
describe 'GET new' do
- def go
- get :new, params: { group_id: group }
+ def go(provider: 'gke')
+ get :new, params: { group_id: group, provider: provider }
end
describe 'functionality for new cluster' do
@@ -97,6 +97,7 @@ describe Groups::ClustersController do
end
before do
+ stub_feature_flags(create_eks_clusters: false)
allow(SecureRandom).to receive(:hex).and_return(key)
end
@@ -106,6 +107,20 @@ describe Groups::ClustersController do
expect(assigns(:authorize_url)).to include(key)
expect(session[session_key_for_redirect_uri]).to eq(new_group_cluster_path(group))
end
+
+ context 'when create_eks_clusters feature flag is enabled' do
+ before do
+ stub_feature_flags(create_eks_clusters: true)
+ end
+
+ context 'when selected provider is gke and no valid gcp token exists' do
+ it 'redirects to gcp authorize_url' do
+ go
+
+ expect(response).to redirect_to(assigns(:authorize_url))
+ end
+ end
+ end
end
context 'when omniauth has not configured' do
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index 35cbab57037..8ac72df5d20 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -79,8 +79,12 @@ describe Projects::ClustersController do
end
describe 'GET new' do
- def go
- get :new, params: { namespace_id: project.namespace, project_id: project }
+ def go(provider: 'gke')
+ get :new, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ provider: provider
+ }
end
describe 'functionality for new cluster' do
@@ -91,6 +95,7 @@ describe Projects::ClustersController do
end
before do
+ stub_feature_flags(create_eks_clusters: false)
allow(SecureRandom).to receive(:hex).and_return(key)
end
@@ -100,6 +105,20 @@ describe Projects::ClustersController do
expect(assigns(:authorize_url)).to include(key)
expect(session[session_key_for_redirect_uri]).to eq(new_project_cluster_path(project))
end
+
+ context 'when create_eks_clusters feature flag is enabled' do
+ before do
+ stub_feature_flags(create_eks_clusters: true)
+ end
+
+ context 'when selected provider is gke and no valid gcp token exists' do
+ it 'redirects to gcp authorize_url' do
+ go
+
+ expect(response).to redirect_to(assigns(:authorize_url))
+ end
+ end
+ end
end
context 'when omniauth has not configured' do
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 180d997a8e8..0c074714bf3 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -19,9 +19,9 @@ describe Projects::ServicesController do
it 'renders 404' do
allow_any_instance_of(Service).to receive(:can_test?).and_return(false)
- put :test, params: { namespace_id: project.namespace, project_id: project, id: service.to_param }
+ put :test, params: project_params
- expect(response).to have_gitlab_http_status(404)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -29,11 +29,11 @@ describe Projects::ServicesController do
let(:service_params) { { active: 'true', url: '' } }
it 'returns error messages in JSON response' do
- put :test, params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params }
+ put :test, params: project_params(service: service_params)
- expect(json_response['message']).to eq "Validations failed."
+ expect(json_response['message']).to eq 'Validations failed.'
expect(json_response['service_response']).to include "Url can't be blank"
- expect(response).to have_gitlab_http_status(200)
+ expect(response).to be_successful
end
end
@@ -47,9 +47,9 @@ describe Projects::ServicesController do
it 'returns success' do
allow_any_instance_of(MicrosoftTeams::Notifier).to receive(:ping).and_return(true)
- put :test, params: { namespace_id: project.namespace, project_id: project, id: service.to_param }
+ put :test, params: project_params
- expect(response.status).to eq(200)
+ expect(response).to be_successful
end
end
@@ -57,11 +57,11 @@ describe Projects::ServicesController do
stub_request(:get, 'http://example.com/rest/api/2/serverInfo')
.to_return(status: 200, body: '{}')
- expect(Gitlab::HTTP).to receive(:get).with("/rest/api/2/serverInfo", any_args).and_call_original
+ expect(Gitlab::HTTP).to receive(:get).with('/rest/api/2/serverInfo', any_args).and_call_original
- put :test, params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params }
+ put :test, params: project_params(service: service_params)
- expect(response.status).to eq(200)
+ expect(response).to be_successful
end
end
@@ -69,14 +69,23 @@ describe Projects::ServicesController do
stub_request(:get, 'http://example.com/rest/api/2/serverInfo')
.to_return(status: 200, body: '{}')
- expect(Gitlab::HTTP).to receive(:get).with("/rest/api/2/serverInfo", any_args).and_call_original
+ expect(Gitlab::HTTP).to receive(:get).with('/rest/api/2/serverInfo', any_args).and_call_original
- put :test, params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params }
+ put :test, params: project_params(service: service_params)
- expect(response.status).to eq(200)
+ expect(response).to be_successful
end
context 'when service is configured for the first time' do
+ let(:service_params) do
+ {
+ 'active' => '1',
+ 'push_events' => '1',
+ 'token' => 'token',
+ 'project_url' => 'http://test.com'
+ }
+ end
+
before do
allow_any_instance_of(ServiceHook).to receive(:execute).and_return(true)
end
@@ -84,7 +93,7 @@ describe Projects::ServicesController do
it 'persist the object' do
do_put
- expect(response).to have_gitlab_http_status(200)
+ expect(response).to be_successful
expect(json_response).to be_empty
expect(BuildkiteService.first).to be_present
end
@@ -92,18 +101,14 @@ describe Projects::ServicesController do
it 'creates the ServiceHook object' do
do_put
- expect(response).to have_gitlab_http_status(200)
+ expect(response).to be_successful
expect(json_response).to be_empty
expect(BuildkiteService.first.service_hook).to be_present
end
def do_put
- put :test, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: 'buildkite',
- service: { 'active' => '1', 'push_events' => '1', token: 'token', 'project_url' => 'http://test.com' }
- }
+ put :test, params: project_params(id: 'buildkite',
+ service: service_params)
end
end
end
@@ -113,9 +118,9 @@ describe Projects::ServicesController do
stub_request(:get, 'http://example.com/rest/api/2/serverInfo')
.to_return(status: 404)
- put :test, params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params }
+ put :test, params: project_params(service: service_params)
- expect(response).to have_gitlab_http_status(200)
+ expect(response).to be_successful
expect(json_response).to eq(
'error' => true,
'message' => 'Test failed.',
@@ -127,39 +132,70 @@ describe Projects::ServicesController do
end
describe 'PUT #update' do
- context 'when param `active` is set to true' do
- it 'activates the service and redirects to integrations paths' do
- put :update,
- params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: true } }
+ describe 'as HTML' do
+ let(:service_params) { { active: true } }
- expect(response).to redirect_to(project_settings_integrations_path(project))
- expect(flash[:notice]).to eq 'Jira activated.'
+ before do
+ put :update, params: project_params(service: service_params)
+ end
+
+ context 'when param `active` is set to true' do
+ it 'activates the service and redirects to integrations paths' do
+ expect(response).to redirect_to(project_settings_integrations_path(project))
+ expect(flash[:notice]).to eq 'Jira activated.'
+ end
+ end
+
+ context 'when param `active` is set to false' do
+ let(:service_params) { { active: false } }
+
+ it 'does not activate the service but saves the settings' do
+ expect(flash[:notice]).to eq 'Jira settings saved, but not activated.'
+ end
end
- end
- context 'when param `active` is set to false' do
- it 'does not activate the service but saves the settings' do
- put :update,
- params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: false } }
+ context 'when activating Jira service from a template' do
+ let(:service) do
+ create(:jira_service, project: project, template: true)
+ end
- expect(flash[:notice]).to eq 'Jira settings saved, but not activated.'
+ it 'activate Jira service from template' do
+ expect(flash[:notice]).to eq 'Jira activated.'
+ end
end
end
- context 'when activating Jira service from a template' do
- let(:template_service) { create(:jira_service, project: project, template: true) }
+ describe 'as JSON' do
+ before do
+ put :update, params: project_params(service: service_params, format: :json)
+ end
+
+ context 'when update succeeds' do
+ let(:service_params) { { url: 'http://example.com' } }
+
+ it 'returns JSON response with no errors' do
+ expect(response).to be_successful
+ expect(json_response).to include('active' => true, 'errors' => {})
+ end
+ end
- it 'activate Jira service from template' do
- put :update, params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: true } }
+ context 'when update fails' do
+ let(:service_params) { { url: '' } }
- expect(flash[:notice]).to eq 'Jira activated.'
+ it 'returns JSON response with errors' do
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response).to include(
+ 'active' => true,
+ 'errors' => { 'url' => ['must be a valid URL', %{can't be blank}] }
+ )
+ end
end
end
end
- describe "GET #edit" do
+ describe 'GET #edit' do
before do
- get :edit, params: { namespace_id: project.namespace, project_id: project, id: 'jira' }
+ get :edit, params: project_params(id: 'jira')
end
context 'with approved services' do
@@ -168,4 +204,14 @@ describe Projects::ServicesController do
end
end
end
+
+ private
+
+ def project_params(opts = {})
+ opts.reverse_merge(
+ namespace_id: project.namespace,
+ project_id: project,
+ id: service.to_param
+ )
+ end
end
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 820ce48e52c..a11237db508 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -18,6 +18,8 @@ describe 'Gcp Cluster', :js do
let(:project_id) { 'test-project-1234' }
before do
+ stub_feature_flags(create_eks_clusters: false)
+
allow_any_instance_of(Projects::ClustersController)
.to receive(:token_in_session).and_return('token')
allow_any_instance_of(Projects::ClustersController)
@@ -147,6 +149,7 @@ describe 'Gcp Cluster', :js do
context 'when user has not signed with Google' do
before do
+ stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project)
click_link 'Add Kubernetes cluster'
diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb
index ce382c19fc1..d1cd19dff2d 100644
--- a/spec/features/projects/clusters_spec.rb
+++ b/spec/features/projects/clusters_spec.rb
@@ -51,6 +51,7 @@ describe 'Clusters', :js do
context 'when user has not signed in Google' do
before do
+ stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project)
click_link 'Add Kubernetes cluster'
@@ -62,4 +63,27 @@ describe 'Clusters', :js do
expect(page).to have_link('Google account')
end
end
+
+ context 'when create_eks_clusters feature flag is enabled' do
+ before do
+ stub_feature_flags(create_eks_clusters: true)
+ end
+
+ context 'when user access create cluster page' do
+ before do
+ visit project_clusters_path(project)
+
+ click_link 'Add Kubernetes cluster'
+ click_link 'Create new Cluster on GKE'
+ end
+
+ it 'user sees a link to create a GKE cluster' do
+ expect(page).to have_link('Google GKE')
+ end
+
+ it 'user sees a link to create an EKS cluster' do
+ expect(page).to have_link('Amazon EKS')
+ end
+ end
+ end
end
diff --git a/spec/fixtures/api/schemas/public_api/v4/tag.json b/spec/fixtures/api/schemas/public_api/v4/tag.json
index 5713ea1f526..bb0190955f0 100644
--- a/spec/fixtures/api/schemas/public_api/v4/tag.json
+++ b/spec/fixtures/api/schemas/public_api/v4/tag.json
@@ -16,7 +16,8 @@
{ "type": "null" },
{ "$ref": "release/tag_release.json" }
]
- }
+ },
+ "protected": { "type": "boolean" }
},
"additionalProperties": false
}
diff --git a/spec/frontend/vue_shared/components/gl_toggle_vuex_spec.js b/spec/frontend/vue_shared/components/gl_toggle_vuex_spec.js
new file mode 100644
index 00000000000..f076c45e56c
--- /dev/null
+++ b/spec/frontend/vue_shared/components/gl_toggle_vuex_spec.js
@@ -0,0 +1,115 @@
+import Vuex from 'vuex';
+import GlToggleVuex from '~/vue_shared/components/gl_toggle_vuex.vue';
+import { GlToggle } from '@gitlab/ui';
+import { mount, createLocalVue } from '@vue/test-utils';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('GlToggleVuex component', () => {
+ let wrapper;
+ let store;
+
+ const findButton = () => wrapper.find('button');
+
+ const createWrapper = (props = {}) => {
+ wrapper = mount(GlToggleVuex, {
+ localVue,
+ store,
+ propsData: {
+ stateProperty: 'toggleState',
+ ...props,
+ },
+ sync: false,
+ });
+ };
+
+ beforeEach(() => {
+ store = new Vuex.Store({
+ state: {
+ toggleState: false,
+ },
+ actions: {
+ setToggleState: ({ commit }, { key, value }) => commit('setToggleState', { key, value }),
+ },
+ mutations: {
+ setToggleState: (state, { key, value }) => {
+ state[key] = value;
+ },
+ },
+ });
+ createWrapper();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders gl-toggle', () => {
+ expect(wrapper.find(GlToggle).exists()).toBe(true);
+ });
+
+ it('properly computes default value for setAction', () => {
+ expect(wrapper.props('setAction')).toBe('setToggleState');
+ });
+
+ describe('without a store module', () => {
+ it('calls action with new value when value changes', () => {
+ jest.spyOn(store, 'dispatch');
+
+ findButton().trigger('click');
+ expect(store.dispatch).toHaveBeenCalledWith('setToggleState', {
+ key: 'toggleState',
+ value: true,
+ });
+ });
+
+ it('updates store property when value changes', () => {
+ findButton().trigger('click');
+ expect(store.state.toggleState).toBe(true);
+ });
+ });
+
+ describe('with a store module', () => {
+ beforeEach(() => {
+ store = new Vuex.Store({
+ modules: {
+ someModule: {
+ namespaced: true,
+ state: {
+ toggleState: false,
+ },
+ actions: {
+ setToggleState: ({ commit }, { key, value }) =>
+ commit('setToggleState', { key, value }),
+ },
+ mutations: {
+ setToggleState: (state, { key, value }) => {
+ state[key] = value;
+ },
+ },
+ },
+ },
+ });
+
+ createWrapper({
+ storeModule: 'someModule',
+ });
+ });
+
+ it('calls action with new value when value changes', () => {
+ jest.spyOn(store, 'dispatch');
+
+ findButton().trigger('click');
+ expect(store.dispatch).toHaveBeenCalledWith('someModule/setToggleState', {
+ key: 'toggleState',
+ value: true,
+ });
+ });
+
+ it('updates store property when value changes', () => {
+ findButton().trigger('click');
+ expect(store.state.someModule.toggleState).toBe(true);
+ });
+ });
+});
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index 3d15306d4d2..e062c841717 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -27,7 +27,7 @@ describe EventsHelper do
end
describe '#event_feed_url' do
- let(:event) { create(:event) }
+ let(:event) { create(:event).present }
let(:project) { create(:project, :public, :repository) }
context 'issue' do
diff --git a/spec/helpers/releases_helper_spec.rb b/spec/helpers/releases_helper_spec.rb
new file mode 100644
index 00000000000..ff820b3cc95
--- /dev/null
+++ b/spec/helpers/releases_helper_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ReleasesHelper do
+ describe '#illustration' do
+ it 'returns the correct image path' do
+ expect(helper.illustration).to match(/illustrations\/releases-(\w+)\.svg/)
+ end
+ end
+
+ describe '#help_page' do
+ it 'returns the correct link to the help page' do
+ expect(helper.help_page).to include('user/project/releases/index')
+ end
+ end
+
+ context 'url helpers' do
+ let(:project) { build(:project, namespace: create(:group)) }
+
+ before do
+ helper.instance_variable_set(:@project, project)
+ end
+
+ describe '#url_for_merge_requests' do
+ it 'returns the the correct link with the correct parameters' do
+ path = "#{project.group.path}/#{project.path}/merge_requests?scope=all&state=opened"
+ expect(helper.url_for_merge_requests).to include(path)
+ end
+ end
+
+ describe '#url_for_issues' do
+ it 'returns the the correct link with the correct parameters' do
+ path = "#{project.group.path}/#{project.path}/issues?scope=all&state=opened"
+ expect(helper.url_for_issues).to include(path)
+ end
+ end
+
+ describe '#data_for_releases_page' do
+ it 'has the needed data to display release blocks' do
+ keys = %i(project_id illustration_path documentation_path merge_requests_url issues_url)
+ expect(helper.data_for_releases_page.keys).to eq(keys)
+ end
+ end
+ end
+end
diff --git a/spec/javascripts/monitoring/components/graph_group_spec.js b/spec/javascripts/monitoring/components/graph_group_spec.js
new file mode 100644
index 00000000000..068c4b5302c
--- /dev/null
+++ b/spec/javascripts/monitoring/components/graph_group_spec.js
@@ -0,0 +1,47 @@
+import { shallowMount } from '@vue/test-utils';
+import GraphGroup from '~/monitoring/components/graph_group.vue';
+
+describe('Graph group component', () => {
+ let graphGroup;
+
+ afterEach(() => {
+ graphGroup.destroy();
+ });
+
+ describe('When groups can be collapsed', () => {
+ beforeEach(() => {
+ graphGroup = shallowMount(GraphGroup, {
+ propsData: {
+ name: 'panel',
+ collapseGroup: true,
+ },
+ });
+ });
+
+ it('should show the angle-down caret icon when collapseGroup is true', () => {
+ expect(graphGroup.vm.caretIcon).toBe('angle-down');
+ });
+
+ it('should show the angle-right caret icon when collapseGroup is false', () => {
+ graphGroup.vm.collapse();
+
+ expect(graphGroup.vm.caretIcon).toBe('angle-right');
+ });
+ });
+
+ describe('When groups can not be collapsed', () => {
+ beforeEach(() => {
+ graphGroup = shallowMount(GraphGroup, {
+ propsData: {
+ name: 'panel',
+ collapseGroup: true,
+ showPanels: false,
+ },
+ });
+ });
+
+ it('should not contain a prometheus-graph-group container when showPanels is false', () => {
+ expect(graphGroup.vm.$el.querySelector('.prometheus-graph-group')).toBe(null);
+ });
+ });
+});
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index dafa4243145..e496ab4cd35 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -376,6 +376,7 @@ project:
- index_status
- feature_usage
- approval_rules
+- approval_merge_request_rules
- approvers
- approver_users
- pages_domains
diff --git a/spec/lib/gitlab/import_export/attributes_finder_spec.rb b/spec/lib/gitlab/import_export/attributes_finder_spec.rb
index 208b60844e3..3cbc1375d6e 100644
--- a/spec/lib/gitlab/import_export/attributes_finder_spec.rb
+++ b/spec/lib/gitlab/import_export/attributes_finder_spec.rb
@@ -20,20 +20,41 @@ describe Gitlab::ImportExport::AttributesFinder do
except: [:iid],
include: [
{ merge_request_diff: {
- include: []
+ include: [],
+ preload: { source_project: nil }
} },
{ merge_request_test: { include: [] } }
],
- only: [:id]
+ only: [:id],
+ preload: {
+ merge_request_diff: { source_project: nil },
+ merge_request_test: nil
+ }
} },
{ commit_statuses: {
- include: [{ commit: { include: [] } }]
+ include: [{ commit: { include: [] } }],
+ preload: { commit: nil }
} },
{ project_members: {
include: [{ user: { include: [],
- only: [:email] } }]
+ only: [:email] } }],
+ preload: { user: nil }
} }
- ]
+ ],
+ preload: {
+ commit_statuses: {
+ commit: nil
+ },
+ issues: nil,
+ labels: nil,
+ merge_requests: {
+ merge_request_diff: { source_project: nil },
+ merge_request_test: nil
+ },
+ project_members: {
+ user: nil
+ }
+ }
}
end
@@ -50,7 +71,8 @@ describe Gitlab::ImportExport::AttributesFinder do
setup_yaml(tree: { project: [:issues] })
is_expected.to match(
- include: [{ issues: { include: [] } }]
+ include: [{ issues: { include: [] } }],
+ preload: { issues: nil }
)
end
@@ -58,7 +80,8 @@ describe Gitlab::ImportExport::AttributesFinder do
setup_yaml(tree: { project: [:project_feature] })
is_expected.to match(
- include: [{ project_feature: { include: [] } }]
+ include: [{ project_feature: { include: [] } }],
+ preload: { project_feature: nil }
)
end
@@ -67,7 +90,8 @@ describe Gitlab::ImportExport::AttributesFinder do
is_expected.to match(
include: [{ issues: { include: [] } },
- { snippets: { include: [] } }]
+ { snippets: { include: [] } }],
+ preload: { issues: nil, snippets: nil }
)
end
@@ -75,7 +99,9 @@ describe Gitlab::ImportExport::AttributesFinder do
setup_yaml(tree: { project: [issues: [:notes]] })
is_expected.to match(
- include: [{ issues: { include: [{ notes: { include: [] } }] } }]
+ include: [{ issues: { include: [{ notes: { include: [] } }],
+ preload: { notes: nil } } }],
+ preload: { issues: { notes: nil } }
)
end
@@ -85,7 +111,9 @@ describe Gitlab::ImportExport::AttributesFinder do
is_expected.to match(
include: [{ merge_requests:
{ include: [{ notes: { include: [] } },
- { merge_request_diff: { include: [] } }] } }]
+ { merge_request_diff: { include: [] } }],
+ preload: { merge_request_diff: nil, notes: nil } } }],
+ preload: { merge_requests: { merge_request_diff: nil, notes: nil } }
)
end
@@ -94,8 +122,11 @@ describe Gitlab::ImportExport::AttributesFinder do
is_expected.to match(
include: [{ merge_requests: {
- include: [{ notes: { include: [{ author: { include: [] } }] } }]
- } }]
+ include: [{ notes: { include: [{ author: { include: [] } }],
+ preload: { author: nil } } }],
+ preload: { notes: { author: nil } }
+ } }],
+ preload: { merge_requests: { notes: { author: nil } } }
)
end
@@ -105,7 +136,8 @@ describe Gitlab::ImportExport::AttributesFinder do
is_expected.to match(
include: [{ issues: { include: [],
- only: [:name, :description] } }]
+ only: [:name, :description] } }],
+ preload: { issues: nil }
)
end
@@ -115,7 +147,8 @@ describe Gitlab::ImportExport::AttributesFinder do
is_expected.to match(
include: [{ issues: { except: [:name],
- include: [] } }]
+ include: [] } }],
+ preload: { issues: nil }
)
end
@@ -127,7 +160,8 @@ describe Gitlab::ImportExport::AttributesFinder do
is_expected.to match(
include: [{ issues: { except: [:name],
include: [],
- only: [:description] } }]
+ only: [:description] } }],
+ preload: { issues: nil }
)
end
@@ -137,7 +171,8 @@ describe Gitlab::ImportExport::AttributesFinder do
is_expected.to match(
include: [{ issues: { include: [],
- methods: [:name] } }]
+ methods: [:name] } }],
+ preload: { issues: nil }
)
end
diff --git a/spec/lib/gitlab/import_export/config_spec.rb b/spec/lib/gitlab/import_export/config_spec.rb
index e53db37def4..f09a29b84db 100644
--- a/spec/lib/gitlab/import_export/config_spec.rb
+++ b/spec/lib/gitlab/import_export/config_spec.rb
@@ -25,7 +25,7 @@ describe Gitlab::ImportExport::Config do
expect { subject }.not_to raise_error
expect(subject).to be_a(Hash)
expect(subject.keys).to contain_exactly(
- :tree, :excluded_attributes, :included_attributes, :methods)
+ :tree, :excluded_attributes, :included_attributes, :methods, :preloads)
end
end
end
@@ -55,6 +55,10 @@ describe Gitlab::ImportExport::Config do
events:
- :action
+ preloads:
+ statuses:
+ project:
+
ee:
tree:
project:
@@ -71,6 +75,9 @@ describe Gitlab::ImportExport::Config do
- :type_ee
events_ee:
- :action_ee
+ preloads:
+ statuses:
+ bridge_ee:
EOF
end
@@ -111,6 +118,11 @@ describe Gitlab::ImportExport::Config do
methods: {
labels: [:type],
events: [:action]
+ },
+ preloads: {
+ statuses: {
+ project: nil
+ }
}
}
)
@@ -150,6 +162,12 @@ describe Gitlab::ImportExport::Config do
labels: [:type, :type_ee],
events: [:action],
events_ee: [:action_ee]
+ },
+ preloads: {
+ statuses: {
+ project: nil,
+ bridge_ee: nil
+ }
}
}
)
diff --git a/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
new file mode 100644
index 00000000000..d23b27c9d8e
--- /dev/null
+++ b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
@@ -0,0 +1,272 @@
+require 'spec_helper'
+
+describe Gitlab::ImportExport::FastHashSerializer do
+ subject { described_class.new(project, tree).execute }
+
+ let!(:project) { setup_project }
+ let(:user) { create(:user) }
+ let(:shared) { project.import_export_shared }
+ let(:reader) { Gitlab::ImportExport::Reader.new(shared: shared) }
+ let(:tree) { reader.project_tree }
+
+ before do
+ project.add_maintainer(user)
+ allow_any_instance_of(MergeRequest).to receive(:source_branch_sha).and_return('ABCD')
+ allow_any_instance_of(MergeRequest).to receive(:target_branch_sha).and_return('DCBA')
+ end
+
+ it 'saves the correct hash' do
+ is_expected.to include({ 'description' => 'description', 'visibility_level' => 20 })
+ end
+
+ it 'has approvals_before_merge set' do
+ expect(subject['approvals_before_merge']).to eq(1)
+ end
+
+ it 'has milestones' do
+ expect(subject['milestones']).not_to be_empty
+ end
+
+ it 'has merge requests' do
+ expect(subject['merge_requests']).not_to be_empty
+ end
+
+ it 'has merge request\'s milestones' do
+ expect(subject['merge_requests'].first['milestone']).not_to be_empty
+ end
+
+ it 'has merge request\'s source branch SHA' do
+ expect(subject['merge_requests'].first['source_branch_sha']).to eq('ABCD')
+ end
+
+ it 'has merge request\'s target branch SHA' do
+ expect(subject['merge_requests'].first['target_branch_sha']).to eq('DCBA')
+ end
+
+ it 'has events' do
+ expect(subject['merge_requests'].first['milestone']['events']).not_to be_empty
+ end
+
+ it 'has snippets' do
+ expect(subject['snippets']).not_to be_empty
+ end
+
+ it 'has snippet notes' do
+ expect(subject['snippets'].first['notes']).not_to be_empty
+ end
+
+ it 'has releases' do
+ expect(subject['releases']).not_to be_empty
+ end
+
+ it 'has no author on releases' do
+ expect(subject['releases'].first['author']).to be_nil
+ end
+
+ it 'has the author ID on releases' do
+ expect(subject['releases'].first['author_id']).not_to be_nil
+ end
+
+ it 'has issues' do
+ expect(subject['issues']).not_to be_empty
+ end
+
+ it 'has issue comments' do
+ notes = subject['issues'].first['notes']
+
+ expect(notes).not_to be_empty
+ expect(notes.first['type']).to eq('DiscussionNote')
+ end
+
+ it 'has issue assignees' do
+ expect(subject['issues'].first['issue_assignees']).not_to be_empty
+ end
+
+ it 'has author on issue comments' do
+ expect(subject['issues'].first['notes'].first['author']).not_to be_empty
+ end
+
+ it 'has project members' do
+ expect(subject['project_members']).not_to be_empty
+ end
+
+ it 'has merge requests diffs' do
+ expect(subject['merge_requests'].first['merge_request_diff']).not_to be_empty
+ end
+
+ it 'has merge request diff files' do
+ expect(subject['merge_requests'].first['merge_request_diff']['merge_request_diff_files']).not_to be_empty
+ end
+
+ it 'has merge request diff commits' do
+ expect(subject['merge_requests'].first['merge_request_diff']['merge_request_diff_commits']).not_to be_empty
+ end
+
+ it 'has merge requests comments' do
+ expect(subject['merge_requests'].first['notes']).not_to be_empty
+ end
+
+ it 'has author on merge requests comments' do
+ expect(subject['merge_requests'].first['notes'].first['author']).not_to be_empty
+ end
+
+ it 'has pipeline stages' do
+ expect(subject.dig('ci_pipelines', 0, 'stages')).not_to be_empty
+ end
+
+ it 'has pipeline statuses' do
+ expect(subject.dig('ci_pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty
+ end
+
+ it 'has pipeline builds' do
+ builds_count = subject
+ .dig('ci_pipelines', 0, 'stages', 0, 'statuses')
+ .count { |hash| hash['type'] == 'Ci::Build' }
+
+ expect(builds_count).to eq(1)
+ end
+
+ it 'has no when YML attributes but only the DB column' do
+ allow_any_instance_of(Ci::Pipeline)
+ .to receive(:ci_yaml_file)
+ .and_return(File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')))
+
+ expect_any_instance_of(Gitlab::Ci::YamlProcessor).not_to receive(:build_attributes)
+
+ subject
+ end
+
+ it 'has pipeline commits' do
+ expect(subject['ci_pipelines']).not_to be_empty
+ end
+
+ it 'has ci pipeline notes' do
+ expect(subject['ci_pipelines'].first['notes']).not_to be_empty
+ end
+
+ it 'has labels with no associations' do
+ expect(subject['labels']).not_to be_empty
+ end
+
+ it 'has labels associated to records' do
+ expect(subject['issues'].first['label_links'].first['label']).not_to be_empty
+ end
+
+ it 'has project and group labels' do
+ label_types = subject['issues'].first['label_links'].map { |link| link['label']['type'] }
+
+ expect(label_types).to match_array(%w(ProjectLabel GroupLabel))
+ end
+
+ it 'has priorities associated to labels' do
+ priorities = subject['issues'].first['label_links'].flat_map { |link| link['label']['priorities'] }
+
+ expect(priorities).not_to be_empty
+ end
+
+ it 'has issue resource label events' do
+ expect(subject['issues'].first['resource_label_events']).not_to be_empty
+ end
+
+ it 'has merge request resource label events' do
+ expect(subject['merge_requests'].first['resource_label_events']).not_to be_empty
+ end
+
+ it 'saves the correct service type' do
+ expect(subject['services'].first['type']).to eq('CustomIssueTrackerService')
+ end
+
+ it 'saves the properties for a service' do
+ expect(subject['services'].first['properties']).to eq('one' => 'value')
+ end
+
+ it 'has project feature' do
+ project_feature = subject['project_feature']
+ expect(project_feature).not_to be_empty
+ expect(project_feature["issues_access_level"]).to eq(ProjectFeature::DISABLED)
+ expect(project_feature["wiki_access_level"]).to eq(ProjectFeature::ENABLED)
+ expect(project_feature["builds_access_level"]).to eq(ProjectFeature::PRIVATE)
+ end
+
+ it 'has custom attributes' do
+ expect(subject['custom_attributes'].count).to eq(2)
+ end
+
+ it 'has badges' do
+ expect(subject['project_badges'].count).to eq(2)
+ end
+
+ it 'does not complain about non UTF-8 characters in MR diff files' do
+ ActiveRecord::Base.connection.execute("UPDATE merge_request_diff_files SET diff = '---\n- :diff: !binary |-\n LS0tIC9kZXYvbnVsbAorKysgYi9pbWFnZXMvbnVjb3IucGRmCkBAIC0wLDAg\n KzEsMTY3OSBAQAorJVBERi0xLjUNJeLjz9MNCisxIDAgb2JqDTw8L01ldGFk\n YXR'")
+
+ expect(subject['merge_requests'].first['merge_request_diff']).not_to be_empty
+ end
+
+ context 'project attributes' do
+ it 'does not contain the runners token' do
+ expect(subject).not_to include("runners_token" => 'token')
+ end
+ end
+
+ it 'has a board and a list' do
+ expect(subject['boards'].first['lists']).not_to be_empty
+ end
+
+ def setup_project
+ issue = create(:issue, assignees: [user])
+ snippet = create(:project_snippet)
+ release = create(:release)
+ group = create(:group)
+
+ project = create(:project,
+ :public,
+ :repository,
+ :issues_disabled,
+ :wiki_enabled,
+ :builds_private,
+ description: 'description',
+ issues: [issue],
+ snippets: [snippet],
+ releases: [release],
+ group: group,
+ approvals_before_merge: 1
+ )
+ project_label = create(:label, project: project)
+ group_label = create(:group_label, group: group)
+ create(:label_link, label: project_label, target: issue)
+ create(:label_link, label: group_label, target: issue)
+ create(:label_priority, label: group_label, priority: 1)
+ milestone = create(:milestone, project: project)
+ merge_request = create(:merge_request, source_project: project, milestone: milestone)
+
+ ci_build = create(:ci_build, project: project, when: nil)
+ ci_build.pipeline.update(project: project)
+ create(:commit_status, project: project, pipeline: ci_build.pipeline)
+
+ create(:milestone, project: project)
+ create(:discussion_note, noteable: issue, project: project)
+ create(:note, noteable: merge_request, project: project)
+ create(:note, noteable: snippet, project: project)
+ create(:note_on_commit,
+ author: user,
+ project: project,
+ commit_id: ci_build.pipeline.sha)
+
+ create(:resource_label_event, label: project_label, issue: issue)
+ create(:resource_label_event, label: group_label, merge_request: merge_request)
+
+ create(:event, :created, target: milestone, project: project, author: user)
+ create(:service, project: project, type: 'CustomIssueTrackerService', category: 'issue_tracker', properties: { one: 'value' })
+
+ create(:project_custom_attribute, project: project)
+ create(:project_custom_attribute, project: project)
+
+ create(:project_badge, project: project)
+ create(:project_badge, project: project)
+
+ board = create(:board, project: project, name: 'TestBoard')
+ create(:list, board: board, position: 0, label: project_label)
+
+ project
+ end
+end
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index fefbed93316..ff46e062a5d 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -23,12 +23,65 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
expect(project_tree_saver.save).to be true
end
+ context ':export_fast_serialize feature flag checks' do
+ before do
+ expect(Gitlab::ImportExport::Reader).to receive(:new).with(shared: shared).and_return(reader)
+ expect(reader).to receive(:project_tree).and_return(project_tree)
+ end
+
+ let(:serializer) { instance_double('Gitlab::ImportExport::FastHashSerializer') }
+ let(:reader) { instance_double('Gitlab::ImportExport::Reader') }
+ let(:project_tree) do
+ {
+ include: [{ issues: { include: [] } }],
+ preload: { issues: nil }
+ }
+ end
+
+ context 'when :export_fast_serialize feature is enabled' do
+ before do
+ stub_feature_flags(export_fast_serialize: true)
+ end
+
+ it 'uses FastHashSerializer' do
+ expect(Gitlab::ImportExport::FastHashSerializer)
+ .to receive(:new)
+ .with(project, project_tree)
+ .and_return(serializer)
+
+ expect(serializer).to receive(:execute)
+
+ project_tree_saver.save
+ end
+ end
+
+ context 'when :export_fast_serialize feature is disabled' do
+ before do
+ stub_feature_flags(export_fast_serialize: false)
+ end
+
+ it 'is serialized via built-in `as_json`' do
+ expect(project).to receive(:as_json).with(project_tree)
+
+ project_tree_saver.save
+ end
+ end
+ end
+
+ # It is mostly duplicated in
+ # `spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb`
+ # except:
+ # context 'with description override' do
+ # context 'group members' do
+ # ^ These are specific for the ProjectTreeSaver
context 'JSON' do
let(:saved_project_json) do
project_tree_saver.save
project_json(project_tree_saver.full_path)
end
+ # It is not duplicated in
+ # `spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb`
context 'with description override' do
let(:params) { { description: 'Foo Bar' } }
let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared, params: params) }
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index 0dbfcf96124..e0b9581c75c 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -4,6 +4,8 @@
require 'spec_helper'
describe Gitlab::ProjectSearchResults do
+ include SearchHelpers
+
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:query) { 'hello world' }
@@ -31,10 +33,10 @@ describe Gitlab::ProjectSearchResults do
where(:scope, :count_method, :expected) do
'blobs' | :blobs_count | '1234'
- 'notes' | :limited_notes_count | '1000+'
+ 'notes' | :limited_notes_count | max_limited_count
'wiki_blobs' | :wiki_blobs_count | '1234'
'commits' | :commits_count | '1234'
- 'projects' | :limited_projects_count | '1000+'
+ 'projects' | :limited_projects_count | max_limited_count
'unknown' | nil | nil
end
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index 5621c686b8a..26cba53502d 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
describe Gitlab::SearchResults do
include ProjectForksHelper
+ include SearchHelpers
let(:user) { create(:user) }
let!(:project) { create(:project, name: 'foo') }
@@ -35,11 +36,11 @@ describe Gitlab::SearchResults do
using RSpec::Parameterized::TableSyntax
where(:scope, :count_method, :expected) do
- 'projects' | :limited_projects_count | '1000+'
- 'issues' | :limited_issues_count | '1000+'
- 'merge_requests' | :limited_merge_requests_count | '1000+'
- 'milestones' | :limited_milestones_count | '1000+'
- 'users' | :limited_users_count | '1000+'
+ 'projects' | :limited_projects_count | max_limited_count
+ 'issues' | :limited_issues_count | max_limited_count
+ 'merge_requests' | :limited_merge_requests_count | max_limited_count
+ 'milestones' | :limited_milestones_count | max_limited_count
+ 'users' | :limited_users_count | max_limited_count
'unknown' | nil | nil
end
@@ -56,9 +57,9 @@ describe Gitlab::SearchResults do
where(:count, :expected) do
23 | '23'
- 1000 | '1000'
- 1001 | '1000+'
- 1234 | '1000+'
+ 100 | '100'
+ 101 | max_limited_count
+ 1234 | max_limited_count
end
with_them do
diff --git a/spec/lib/gitlab/snippet_search_results_spec.rb b/spec/lib/gitlab/snippet_search_results_spec.rb
index 89d290aaa81..d3353b76c15 100644
--- a/spec/lib/gitlab/snippet_search_results_spec.rb
+++ b/spec/lib/gitlab/snippet_search_results_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
describe Gitlab::SnippetSearchResults do
+ include SearchHelpers
+
let!(:snippet) { create(:snippet, content: 'foo', file_name: 'foo') }
let(:results) { described_class.new(Snippet.all, 'foo') }
@@ -25,7 +27,7 @@ describe Gitlab::SnippetSearchResults do
where(:scope, :count_method, :expected) do
'snippet_titles' | :snippet_titles_count | '1234'
'snippet_blobs' | :snippet_blobs_count | '1234'
- 'projects' | :limited_projects_count | '1000+'
+ 'projects' | :limited_projects_count | max_limited_count
'unknown' | nil | nil
end
diff --git a/spec/presenters/event_presenter_spec.rb b/spec/presenters/event_presenter_spec.rb
new file mode 100644
index 00000000000..79f5e359141
--- /dev/null
+++ b/spec/presenters/event_presenter_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe EventPresenter do
+ include Gitlab::Routing.url_helpers
+
+ set(:group) { create(:group) }
+ set(:project) { create(:project, group: group) }
+ set(:target) { create(:milestone, project: project) }
+ set(:group_event) { create(:event, :created, project: nil, group: group, target: target) }
+ set(:project_event) { create(:event, :created, project: project, target: target) }
+
+ describe '#resource_parent_name' do
+ context 'with group event' do
+ subject { group_event.present.resource_parent_name }
+
+ it { is_expected.to eq(group.full_name) }
+ end
+
+ context 'with project label' do
+ subject { project_event.present.resource_parent_name }
+
+ it { is_expected.to eq(project.full_name) }
+ end
+ end
+
+ describe '#target_link_options' do
+ context 'with group event' do
+ subject { group_event.present.target_link_options }
+
+ it { is_expected.to eq([group, target]) }
+ end
+
+ context 'with project label' do
+ subject { project_event.present.target_link_options }
+
+ it { is_expected.to eq([group.becomes(Namespace), project, target]) }
+ end
+ end
+end
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 048d04cdefd..d98b9be726a 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -252,5 +252,43 @@ describe API::Settings, 'Settings' do
expect(json_response['asset_proxy_whitelist']).to eq(['example.com', '*.example.com', 'localhost'])
end
end
+
+ context 'domain_blacklist settings' do
+ it 'rejects domain_blacklist_enabled when domain_blacklist is empty' do
+ put api('/application/settings', admin),
+ params: {
+ domain_blacklist_enabled: true,
+ domain_blacklist: []
+ }
+
+ expect(response).to have_gitlab_http_status(400)
+ message = json_response["message"]
+ expect(message["domain_blacklist"]).to eq(["Domain blacklist cannot be empty if Blacklist is enabled."])
+ end
+
+ it 'allows array for domain_blacklist' do
+ put api('/application/settings', admin),
+ params: {
+ domain_blacklist_enabled: true,
+ domain_blacklist: ['domain1.com', 'domain2.com']
+ }
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['domain_blacklist_enabled']).to be(true)
+ expect(json_response['domain_blacklist']).to eq(['domain1.com', 'domain2.com'])
+ end
+
+ it 'allows a string for domain_blacklist' do
+ put api('/application/settings', admin),
+ params: {
+ domain_blacklist_enabled: true,
+ domain_blacklist: 'domain3.com, *.domain4.com'
+ }
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['domain_blacklist_enabled']).to be(true)
+ expect(json_response['domain_blacklist']).to eq(['domain3.com', '*.domain4.com'])
+ end
+ end
end
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 8a3de2a52fc..7e2d70d6eb5 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -530,15 +530,22 @@ describe 'project routing' do
end
end
- # project_blame GET /:project_id/blame/:id(.:format) blame#show {id: /.+/, project_id: /[^\/]+/}
+ # project_blame GET /:project_id/blame/:id(.:format) blame#show {id: /[^\0]+/, project_id: /[^\/]+/}
describe Projects::BlameController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/blame/master/app/models/project.rb')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
expect(get('/gitlab/gitlabhq/blame/master/files.scss')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/blame/master/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/blame', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/#{newline_file}" })
end
end
- # project_blob GET /:project_id/blob/:id(.:format) blob#show {id: /.+/, project_id: /[^\/]+/}
+ # project_blob GET /:project_id/blob/:id(.:format) blob#show {id: /[^\0]+/, project_id: /[^\/]+/}
describe Projects::BlobController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/blob/master/app/models/project.rb')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
@@ -547,28 +554,56 @@ describe 'project routing' do
expect(get('/gitlab/gitlabhq/blob/master/files.scss')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss')
expect(get('/gitlab/gitlabhq/blob/master/blob/index.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/blob/index.js')
expect(get('/gitlab/gitlabhq/blob/blob/master/blob/index.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'blob/master/blob/index.js')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/blob/blob/master/blob/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/blob', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "blob/master/blob/#{newline_file}" })
end
end
- # project_tree GET /:project_id/tree/:id(.:format) tree#show {id: /.+/, project_id: /[^\/]+/}
+ # project_tree GET /:project_id/tree/:id(.:format) tree#show {id: /[^\0]+/, project_id: /[^\/]+/}
describe Projects::TreeController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/tree/master/app/models/project.rb')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
expect(get('/gitlab/gitlabhq/tree/master/files.scss')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss')
expect(get('/gitlab/gitlabhq/tree/master/tree/files')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/tree/files')
expect(get('/gitlab/gitlabhq/tree/tree/master/tree/files')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'tree/master/tree/files')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/tree/master/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/tree', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/#{newline_file}" })
end
end
- # project_find_file GET /:namespace_id/:project_id/find_file/*id(.:format) projects/find_file#show {:id=>/.+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?<!\.atom)/, :format=>/html/}
+ # project_find_file GET /:namespace_id/:project_id/find_file/*id(.:format) projects/find_file#show {:id=>/[^\0]+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?<!\.atom)/, :format=>/html/}
# project_files GET /:namespace_id/:project_id/files/*id(.:format) projects/find_file#list {:id=>/(?:[^.]|\.(?!json$))+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?<!\.atom)/, :format=>/json/}
describe Projects::FindFileController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/find_file/master')).to route_to('projects/find_file#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/find_file/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/find_file', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "#{newline_file}" })
end
it 'to #list' do
expect(get('/gitlab/gitlabhq/files/master.json')).to route_to('projects/find_file#list', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master.json')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/files/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/find_file', action: 'list',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "#{newline_file}" })
end
end
@@ -578,6 +613,13 @@ describe 'project routing' do
route_to('projects/blob#edit',
namespace_id: 'gitlab', project_id: 'gitlabhq',
id: 'master/app/models/project.rb'))
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/edit/master/docs/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/blob', action: 'edit',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/docs/#{newline_file}" })
end
it 'to #preview' do
@@ -585,6 +627,26 @@ describe 'project routing' do
route_to('projects/blob#preview',
namespace_id: 'gitlab', project_id: 'gitlabhq',
id: 'master/app/models/project.rb'))
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/edit/master/docs/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/blob', action: 'edit',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/docs/#{newline_file}" })
+ end
+ end
+
+ # project_raw GET /:project_id/raw/:id(.:format) raw#show {id: /[^\0]+/, project_id: /[^\/]+/}
+ describe Projects::RawController, 'routing' do
+ it 'to #show' do
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/raw/master/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/raw', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/#{newline_file}" })
end
end
diff --git a/spec/support/helpers/search_helpers.rb b/spec/support/helpers/search_helpers.rb
index 2cf3f4b83c4..d1d25fbabcd 100644
--- a/spec/support/helpers/search_helpers.rb
+++ b/spec/support/helpers/search_helpers.rb
@@ -19,4 +19,8 @@ module SearchHelpers
click_link scope
end
end
+
+ def max_limited_count
+ Gitlab::SearchResults::COUNT_LIMIT_MESSAGE
+ end
end
diff --git a/spec/support/import_export/import_export.yml b/spec/support/import_export/import_export.yml
index ed2a3243f0d..116bc8d0b9c 100644
--- a/spec/support/import_export/import_export.yml
+++ b/spec/support/import_export/import_export.yml
@@ -13,6 +13,10 @@ tree:
group_members:
- :user
+preloads:
+ merge_request_diff:
+ source_project:
+
included_attributes:
merge_requests:
- :id
diff --git a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
index 76d82649c5f..f2f31e1b7f2 100644
--- a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
+++ b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
shared_examples_for 'multiple issue boards' do
- dropdown_selector = '.js-boards-selector .dropdown-menu'
-
context 'authorized user' do
before do
parent.add_maintainer(user)
@@ -20,18 +18,14 @@ shared_examples_for 'multiple issue boards' do
end
it 'shows a list of boards' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
expect(page).to have_content(board.name)
expect(page).to have_content(board2.name)
end
end
it 'switches current board' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_link board2.name
end
@@ -43,9 +37,7 @@ shared_examples_for 'multiple issue boards' do
end
it 'creates new board without detailed configuration' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_button 'Create new board'
end
@@ -57,28 +49,23 @@ shared_examples_for 'multiple issue boards' do
end
it 'deletes board' do
- click_button board.name
-
- wait_for_requests
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_button 'Delete board'
end
expect(page).to have_content('Are you sure you want to delete this board?')
click_button 'Delete'
- click_button board2.name
- page.within(dropdown_selector) do
+ wait_for_requests
+
+ in_boards_switcher_dropdown do
expect(page).not_to have_content(board.name)
expect(page).to have_content(board2.name)
end
end
it 'adds a list to the none default board' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_link board2.name
end
@@ -100,9 +87,7 @@ shared_examples_for 'multiple issue boards' do
expect(page).to have_selector('.board', count: 3)
- click_button board2.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_link board.name
end
@@ -114,9 +99,9 @@ shared_examples_for 'multiple issue boards' do
it 'maintains sidebar state over board switch' do
assert_boards_nav_active
- find('.boards-switcher').click
- wait_for_requests
- click_link board2.name
+ in_boards_switcher_dropdown do
+ click_link board2.name
+ end
assert_boards_nav_active
end
@@ -129,15 +114,24 @@ shared_examples_for 'multiple issue boards' do
end
it 'does not show action links' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
expect(page).not_to have_content('Create new board')
expect(page).not_to have_content('Delete board')
end
end
end
+ def in_boards_switcher_dropdown
+ find('.boards-switcher').click
+
+ wait_for_requests
+
+ dropdown_selector = '.js-boards-selector .dropdown-menu'
+ page.within(dropdown_selector) do
+ yield
+ end
+ end
+
def assert_boards_nav_active
expect(find('.nav-sidebar .active .active')).to have_selector('a', text: 'Boards')
end