diff options
author | Stan Hu <stanhu@gmail.com> | 2019-08-07 09:04:49 -0700 |
---|---|---|
committer | Stan Hu <stanhu@gmail.com> | 2019-08-07 09:04:49 -0700 |
commit | 4f1997a05a3d8d8eb04949888eff4c6a92de1bc3 (patch) | |
tree | ee4654944cfa7a5609ef54569301e975a03c2c74 | |
parent | 971c1061b22ac921c32d194dd67b67819d1ac74d (diff) | |
parent | 8d659869e1d8ef4a844ea03890f42cb80f312fa0 (diff) | |
download | gitlab-ce-44496-save-project-id.tar.gz |
Merge branch 'master' into 44496-save-project-id44496-save-project-id
416 files changed, 2629 insertions, 1255 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index cb3bc544132..dae3c349ff4 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -6,8 +6,8 @@ /doc/ @axil @marcia @eread @mikelewis # Frontend maintainers should see everything in `app/assets/` -app/assets/ @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya @pslaughter -*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya @pslaughter +app/assets/ @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter +*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter # Maintainers from the Database team should review changes in `db/` db/ @gl-database diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml index ed6690c1023..4a9269ffd82 100644 --- a/.gitlab/ci/review.gitlab-ci.yml +++ b/.gitlab/ci/review.gitlab-ci.yml @@ -7,6 +7,7 @@ except: refs: - master + - /^\d+-\d+-auto-deploy-\d+$/ - /(^docs[\/-].+|.+-docs$)/ .review-schedules-only: &review-schedules-only @@ -264,6 +265,7 @@ danger-review: except: refs: - master + - /^\d+-\d+-auto-deploy-\d+$/ - /^[\d-]+-stable(-ee)?$/ variables: - $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/ @@ -170,7 +170,7 @@ gem 'acts-as-taggable-on', '~> 6.0' gem 'sidekiq', '~> 5.2.7' gem 'sidekiq-cron', '~> 1.0' gem 'redis-namespace', '~> 1.6.0' -gem 'gitlab-sidekiq-fetcher', '~> 0.4.0', require: 'sidekiq-reliable-fetch' +gem 'gitlab-sidekiq-fetcher', '0.5.1', require: 'sidekiq-reliable-fetch' # Cron Parser gem 'fugit', '~> 1.2.1' @@ -296,7 +296,6 @@ gem 'batch-loader', '~> 1.4.0' # Perf bar gem 'peek', '~> 1.0.1' -gem 'peek-gc', '~> 0.0.2' # Memory benchmarks gem 'derailed_benchmarks', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 769af1fa20e..80f36a9457c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -319,7 +319,7 @@ GEM jaeger-client (~> 0.10) opentracing (~> 0.4) gitlab-markup (1.7.0) - gitlab-sidekiq-fetcher (0.4.0) + gitlab-sidekiq-fetcher (0.5.1) sidekiq (~> 5) gitlab-styles (2.8.0) rubocop (~> 0.69.0) @@ -522,7 +522,7 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2019.0331) mimemagic (0.3.2) - mini_magick (4.8.0) + mini_magick (4.9.5) mini_mime (1.0.1) mini_portile2 (2.4.0) minitest (5.11.3) @@ -641,8 +641,6 @@ GEM concurrent-ruby (>= 0.9.0) concurrent-ruby-ext (>= 0.9.0) railties (>= 4.0.0) - peek-gc (0.0.2) - peek pg (1.1.4) po_to_json (1.0.1) json (>= 1.6.0) @@ -1102,7 +1100,7 @@ DEPENDENCIES github-markup (~> 1.7.0) gitlab-labkit (~> 0.3.0) gitlab-markup (~> 1.7.0) - gitlab-sidekiq-fetcher (~> 0.4.0) + gitlab-sidekiq-fetcher (= 0.5.1) gitlab-styles (~> 2.7) gitlab_omniauth-ldap (~> 2.1.1) gon (~> 6.2) @@ -1173,7 +1171,6 @@ DEPENDENCIES omniauth_openid_connect (~> 0.3.1) org-ruby (~> 0.9.12) peek (~> 1.0.1) - peek-gc (~> 0.0.2) pg (~> 1.1) premailer-rails (~> 1.9.7) prometheus-client-mmap (~> 0.9.8) diff --git a/app/assets/javascripts/behaviors/preview_markdown.js b/app/assets/javascripts/behaviors/preview_markdown.js index 35874140bf9..b2571fb840c 100644 --- a/app/assets/javascripts/behaviors/preview_markdown.js +++ b/app/assets/javascripts/behaviors/preview_markdown.js @@ -36,6 +36,10 @@ MarkdownPreview.prototype.showPreview = function($form) { mdText = $form.find('textarea.markdown-area').val(); + if (mdText === undefined) { + return; + } + if (mdText.trim().length === 0) { preview.text(this.emptyMessage); this.hideReferencedUsers($form); diff --git a/app/assets/javascripts/boards/services/board_service.js b/app/assets/javascripts/boards/services/board_service.js index 5202620057c..56a6cab6c73 100644 --- a/app/assets/javascripts/boards/services/board_service.js +++ b/app/assets/javascripts/boards/services/board_service.js @@ -1,4 +1,9 @@ /* eslint-disable class-methods-use-this */ +/** + * This file is intended to be deleted. + * The existing functions will removed one by one in favor of using the board store directly. + * see https://gitlab.com/gitlab-org/gitlab-ce/issues/61621 + */ import boardsStore from '~/boards/stores/boards_store'; diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 5e90893b684..31c4a920bbe 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -44,6 +44,11 @@ export const isInIssuePage = () => checkPageAndAction('issues', 'show'); export const isInMRPage = () => checkPageAndAction('merge_requests', 'show'); export const isInEpicPage = () => checkPageAndAction('epics', 'show'); +export const getCspNonceValue = () => { + const metaTag = document.querySelector('meta[name=csp-nonce]'); + return metaTag && metaTag.content; +}; + export const ajaxGet = url => axios .get(url, { @@ -51,7 +56,7 @@ export const ajaxGet = url => responseType: 'text', }) .then(({ data }) => { - $.globalEval(data); + $.globalEval(data, { nonce: getCspNonceValue() }); }); export const rstrip = val => { diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 45543ef2cc8..2feb545199b 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -1,5 +1,12 @@ <script> -import { GlButton, GlDropdown, GlDropdownItem, GlModal, GlModalDirective } from '@gitlab/ui'; +import { + GlButton, + GlDropdown, + GlDropdownItem, + GlModal, + GlModalDirective, + GlTooltipDirective, +} from '@gitlab/ui'; import _ from 'underscore'; import { mapActions, mapState } from 'vuex'; import { s__ } from '~/locale'; @@ -30,7 +37,8 @@ export default { GlModal, }, directives: { - GlModalDirective, + GlModal: GlModalDirective, + GlTooltip: GlTooltipDirective, }, props: { externalDashboardUrl: { @@ -328,7 +336,7 @@ export default { <div class="d-flex"> <div v-if="addingMetricsAvailable"> <gl-button - v-gl-modal-directive="$options.addMetric.modalId" + v-gl-modal="$options.addMetric.modalId" class="js-add-metric-button text-success border-success" >{{ $options.addMetric.title }}</gl-button > @@ -395,14 +403,35 @@ export default { :project-path="projectPath" group-id="monitor-area-chart" > - <alert-widget - v-if="alertWidgetAvailable && graphData" - :alerts-endpoint="alertsEndpoint" - :relevant-queries="graphData.queries" - :alerts-to-manage="getGraphAlerts(graphData.queries)" - :modal-id="`alert-modal-${index}-${graphIndex}`" - @setAlerts="setAlerts" - /> + <div class="d-flex align-items-center"> + <alert-widget + v-if="alertWidgetAvailable && graphData" + :modal-id="`alert-modal-${index}-${graphIndex}`" + :alerts-endpoint="alertsEndpoint" + :relevant-queries="graphData.queries" + :alerts-to-manage="getGraphAlerts(graphData.queries)" + @setAlerts="setAlerts" + /> + <gl-dropdown + v-if="alertWidgetAvailable" + v-gl-tooltip + class="mx-2" + toggle-class="btn btn-transparent border-0" + :right="true" + :no-caret="true" + :title="__('More actions')" + > + <template slot="button-content"> + <icon name="ellipsis_v" class="text-secondary" /> + </template> + <gl-dropdown-item + v-if="alertWidgetAvailable" + v-gl-modal="`alert-modal-${index}-${graphIndex}`" + > + {{ __('Alerts') }} + </gl-dropdown-item> + </gl-dropdown> + </div> </monitor-area-chart> </template> </graph-group> diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue index f1f02964a29..295c0851f12 100644 --- a/app/assets/javascripts/monitoring/components/panel_type.vue +++ b/app/assets/javascripts/monitoring/components/panel_type.vue @@ -1,6 +1,7 @@ <script> import { mapState } from 'vuex'; import _ from 'underscore'; +import { GlDropdown, GlDropdownItem, GlModal, GlModalDirective } from '@gitlab/ui'; import MonitorAreaChart from './charts/area.vue'; import MonitorSingleStatChart from './charts/single_stat.vue'; import MonitorEmptyChart from './charts/empty_chart.vue'; @@ -10,6 +11,12 @@ export default { MonitorAreaChart, MonitorSingleStatChart, MonitorEmptyChart, + GlDropdown, + GlDropdownItem, + GlModal, + }, + directives: { + GlModal: GlModalDirective, }, props: { graphData: { @@ -64,14 +71,32 @@ export default { :container-width="dashboardWidth" group-id="monitor-area-chart" > - <alert-widget - v-if="alertWidgetAvailable" - :alerts-endpoint="alertsEndpoint" - :relevant-queries="graphData.queries" - :alerts-to-manage="getGraphAlerts(graphData.queries)" - :modal-id="`alert-modal-${index}`" - @setAlerts="setAlerts" - /> + <div class="d-flex align-items-center"> + <alert-widget + v-if="alertWidgetAvailable && graphData" + :modal-id="`alert-modal-${index}`" + :alerts-endpoint="alertsEndpoint" + :relevant-queries="graphData.queries" + :alerts-to-manage="getGraphAlerts(graphData.queries)" + @setAlerts="setAlerts" + /> + <gl-dropdown + v-if="alertWidgetAvailable" + v-gl-tooltip + class="mx-2" + toggle-class="btn btn-transparent border-0" + :right="true" + :no-caret="true" + :title="__('More actions')" + > + <template slot="button-content"> + <icon name="ellipsis_v" class="text-secondary" /> + </template> + <gl-dropdown-item v-if="alertWidgetAvailable" v-gl-modal="`alert-modal-${index}`"> + {{ __('Alerts') }} + </gl-dropdown-item> + </gl-dropdown> + </div> </monitor-area-chart> <monitor-empty-chart v-else :graph-title="graphData.title" /> </template> diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue index c0ea42ad1a2..13aa8844172 100644 --- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue +++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue @@ -112,12 +112,6 @@ export default { :header="metric.header" :keys="metric.keys" /> - <div id="peek-view-gc" class="view"> - <span v-if="currentRequest.details" class="bold"> - <span title="Invoke Time">{{ currentRequest.details.gc.gc_time }}</span - >ms / <span title="Invoke Count">{{ currentRequest.details.gc.invokes }}</span> gc - </span> - </div> <div v-if="currentRequest.details && currentRequest.details.tracing" id="peek-view-trace" diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue index 244d332f38f..4b2d816c6a0 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_actions.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue @@ -1,9 +1,11 @@ <script> import { GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui'; -import { s__, sprintf } from '~/locale'; +import axios from '~/lib/utils/axios_utils'; +import flash from '~/flash'; +import { s__, __, sprintf } from '~/locale'; import GlCountdown from '~/vue_shared/components/gl_countdown.vue'; +import Icon from '~/vue_shared/components/icon.vue'; import eventHub from '../event_hub'; -import Icon from '../../vue_shared/components/icon.vue'; export default { directives: { @@ -44,7 +46,24 @@ export default { this.isLoading = true; - eventHub.$emit('postAction', action.path); + /** + * Ideally, the component would not make an api call directly. + * However, in order to use the eventhub and know when to + * toggle back the `isLoading` property we'd need an ID + * to track the request with a wacther - since this component + * is rendered at least 20 times in the same page, moving the + * api call directly here is the most performant solution + */ + axios + .post(`${action.path}.json`) + .then(() => { + this.isLoading = false; + eventHub.$emit('updateTable'); + }) + .catch(() => { + this.isLoading = false; + flash(__('An error occurred while making the request.')); + }); }, isActionDisabled(action) { diff --git a/app/assets/javascripts/pipelines/mixins/pipelines.js b/app/assets/javascripts/pipelines/mixins/pipelines.js index a6243366375..126a9a47a2b 100644 --- a/app/assets/javascripts/pipelines/mixins/pipelines.js +++ b/app/assets/javascripts/pipelines/mixins/pipelines.js @@ -60,12 +60,14 @@ export default { eventHub.$on('postAction', this.postAction); eventHub.$on('retryPipeline', this.postAction); eventHub.$on('clickedDropdown', this.updateTable); + eventHub.$on('updateTable', this.updateTable); eventHub.$on('refreshPipelinesTable', this.fetchPipelines); }, beforeDestroy() { eventHub.$off('postAction', this.postAction); eventHub.$off('retryPipeline', this.postAction); eventHub.$off('clickedDropdown', this.updateTable); + eventHub.$off('updateTable', this.updateTable); eventHub.$off('refreshPipelinesTable', this.fetchPipelines); }, destroyed() { diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue index ae9b013d980..f7c508c4e23 100644 --- a/app/assets/javascripts/vue_shared/components/commit.vue +++ b/app/assets/javascripts/vue_shared/components/commit.vue @@ -152,37 +152,35 @@ export default { :href="mergeRequestRef.path" :title="mergeRequestRef.title" class="ref-name" + >{{ mergeRequestRef.iid }}</gl-link > - {{ mergeRequestRef.iid }} - </gl-link> <gl-link v-else v-gl-tooltip :href="commitRef.ref_url" :title="commitRef.name" class="ref-name" + >{{ commitRef.name }}</gl-link > - {{ commitRef.name }} - </gl-link> </template> <icon name="commit" class="commit-icon js-commit-icon" /> - <gl-link :href="commitUrl" class="commit-sha mr-0"> {{ shortSha }} </gl-link> + <gl-link :href="commitUrl" class="commit-sha mr-0">{{ shortSha }}</gl-link> - <div class="commit-title flex-truncate-parent"> - <tooltip-on-truncate v-if="title" class="flex-truncate-child" :title="title"> + <div class="commit-title"> + <span v-if="title" class="flex-truncate-parent"> <user-avatar-link v-if="hasAuthor" :link-href="author.path" :img-src="author.avatar_url" :img-alt="userImageAltDescription" :tooltip-text="author.username" - class="avatar-image-container" + class="avatar-image-container text-decoration-none" /> - <gl-link :href="commitUrl" class="commit-row-message cgray"> - {{ title }} - </gl-link> - </tooltip-on-truncate> + <tooltip-on-truncate :title="title" class="flex-truncate-child"> + <gl-link :href="commitUrl" class="commit-row-message cgray">{{ title }}</gl-link> + </tooltip-on-truncate> + </span> <span v-else>{{ __("Can't find HEAD commit for this branch") }}</span> </div> </div> diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue index fc6a45b957e..6a4a834337a 100644 --- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue @@ -27,7 +27,6 @@ export default { return { width: 0, height: 0, - isLoaded: false, }; }, computed: { @@ -63,8 +62,6 @@ export default { this.height = contentImg.naturalHeight; this.$nextTick(() => { - this.isLoaded = true; - this.$emit('imgLoaded', { width: this.width, height: this.height, diff --git a/app/assets/stylesheets/framework/responsive_tables.scss b/app/assets/stylesheets/framework/responsive_tables.scss index 6bd44ee19bd..fd6f80e26cb 100644 --- a/app/assets/stylesheets/framework/responsive_tables.scss +++ b/app/assets/stylesheets/framework/responsive_tables.scss @@ -155,7 +155,7 @@ text-overflow: ellipsis; @include media-breakpoint-up(md) { - flex: 0 0 90%; + flex: 0 0 85%; } .avatar { diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index 21b3949e361..3489ea78b77 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -194,10 +194,9 @@ module IssuableCollections end def collection_type - @collection_type ||= case finder_type.name - when 'IssuesFinder' + @collection_type ||= if finder_type <= IssuesFinder 'Issue' - when 'MergeRequestsFinder' + elsif finder_type <= MergeRequestsFinder 'MergeRequest' end end diff --git a/app/finders/clusters/knative_services_finder.rb b/app/finders/clusters/knative_services_finder.rb index 7d3b53ef663..71cebe4495e 100644 --- a/app/finders/clusters/knative_services_finder.rb +++ b/app/finders/clusters/knative_services_finder.rb @@ -13,11 +13,11 @@ module Clusters self.reactive_cache_key = ->(finder) { finder.model_name } self.reactive_cache_worker_finder = ->(_id, *cache_args) { from_cache(*cache_args) } - attr_reader :cluster, :project + attr_reader :cluster, :environment - def initialize(cluster, project) + def initialize(cluster, environment) @cluster = cluster - @project = project + @environment = environment end def with_reactive_cache_memoized(*cache_args, &block) @@ -30,11 +30,11 @@ module Clusters clear_reactive_cache!(*cache_args) end - def self.from_cache(cluster_id, project_id) + def self.from_cache(cluster_id, environment_id) cluster = Clusters::Cluster.find(cluster_id) - project = ::Project.find(project_id) + environment = Environment.find(environment_id) - new(cluster, project) + new(cluster, environment) end def calculate_reactive_cache(*) @@ -56,7 +56,7 @@ module Clusters end def cache_args - [cluster.id, project.id] + [cluster.id, environment.id] end def service_pod_details(service) @@ -84,7 +84,7 @@ module Clusters private def search_namespace - @search_namespace ||= cluster.kubernetes_namespace_for(project) + @search_namespace ||= cluster.kubernetes_namespace_for(environment) end def knative_client diff --git a/app/finders/clusters/kubernetes_namespace_finder.rb b/app/finders/clusters/kubernetes_namespace_finder.rb new file mode 100644 index 00000000000..e947796c1e7 --- /dev/null +++ b/app/finders/clusters/kubernetes_namespace_finder.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Clusters + class KubernetesNamespaceFinder + attr_reader :cluster, :project, :environment_slug + + def initialize(cluster, project:, environment_slug:, allow_blank_token: false) + @cluster = cluster + @project = project + @environment_slug = environment_slug + @allow_blank_token = allow_blank_token + end + + def execute + find_namespace(with_environment: cluster.namespace_per_environment?) + end + + private + + attr_reader :allow_blank_token + + def find_namespace(with_environment:) + relation = with_environment ? namespaces.with_environment_slug(environment_slug) : namespaces + + relation.find_by_project_id(project.id) + end + + def namespaces + if allow_blank_token + cluster.kubernetes_namespaces + else + cluster.kubernetes_namespaces.has_service_account_token + end + end + end +end diff --git a/app/finders/projects/serverless/functions_finder.rb b/app/finders/projects/serverless/functions_finder.rb index ebe50806ca1..e8c50ef1a88 100644 --- a/app/finders/projects/serverless/functions_finder.rb +++ b/app/finders/projects/serverless/functions_finder.rb @@ -3,10 +3,11 @@ module Projects module Serverless class FunctionsFinder + include Gitlab::Utils::StrongMemoize + attr_reader :project def initialize(project) - @clusters = project.clusters @project = project end @@ -16,9 +17,8 @@ module Projects # Possible return values: Clusters::KnativeServicesFinder::KNATIVE_STATE def knative_installed - states = @clusters.map do |cluster| - cluster.application_knative - cluster.knative_services_finder(project).knative_detected.tap do |state| + states = services_finders.map do |finder| + finder.knative_detected.tap do |state| return state if state == ::Clusters::KnativeServicesFinder::KNATIVE_STATES['checking'] # rubocop:disable Cop/AvoidReturnFromBlocks end end @@ -31,66 +31,70 @@ module Projects end def invocation_metrics(environment_scope, name) - return unless prometheus_adapter&.can_query? + environment = finders_for_scope(environment_scope).first&.environment - cluster = @clusters.find do |c| - environment_scope == c.environment_scope + if environment.present? && environment.prometheus_adapter&.can_query? + func = ::Serverless::Function.new(project, name, environment.deployment_namespace) + environment.prometheus_adapter.query(:knative_invocation, func) end - - func = ::Serverless::Function.new(project, name, cluster.kubernetes_namespace_for(project)) - prometheus_adapter.query(:knative_invocation, func) end def has_prometheus?(environment_scope) - @clusters.any? do |cluster| - environment_scope == cluster.environment_scope && cluster.application_prometheus_available? + finders_for_scope(environment_scope).any? do |finder| + finder.cluster.application_prometheus_available? end end private def knative_service(environment_scope, name) - @clusters.map do |cluster| - next if environment_scope != cluster.environment_scope - - services = cluster - .knative_services_finder(project) + finders_for_scope(environment_scope).map do |finder| + services = finder .services .select { |svc| svc["metadata"]["name"] == name } - add_metadata(cluster, services).first unless services.nil? + add_metadata(finder, services).first unless services.nil? end end def knative_services - @clusters.map do |cluster| - services = cluster - .knative_services_finder(project) - .services + services_finders.map do |finder| + services = finder.services - add_metadata(cluster, services) unless services.nil? + add_metadata(finder, services) unless services.nil? end end - def add_metadata(cluster, services) + def add_metadata(finder, services) + add_pod_count = services.one? + services.each do |s| - s["environment_scope"] = cluster.environment_scope - s["cluster_id"] = cluster.id + s["environment_scope"] = finder.cluster.environment_scope + s["cluster_id"] = finder.cluster.id - if services.length == 1 - s["podcount"] = cluster - .knative_services_finder(project) + if add_pod_count + s["podcount"] = finder .service_pod_details(s["metadata"]["name"]) .length end end end - # rubocop: disable CodeReuse/ServiceClass - def prometheus_adapter - @prometheus_adapter ||= ::Prometheus::AdapterService.new(project).prometheus_adapter + def services_finders + strong_memoize(:services_finders) do + available_environments.map(&:knative_services_finder).compact + end + end + + def available_environments + @project.environments.available.preload_cluster + end + + def finders_for_scope(environment_scope) + services_finders.select do |finder| + environment_scope == finder.cluster.environment_scope + end end - # rubocop: enable CodeReuse/ServiceClass end end end diff --git a/app/models/active_session.rb b/app/models/active_session.rb index fdd210f0fba..00192b1da59 100644 --- a/app/models/active_session.rb +++ b/app/models/active_session.rb @@ -136,8 +136,10 @@ class ActiveSession # only the single key entries are automatically expired by redis, the # lookup entries in the set need to be removed manually. session_ids_and_entries = session_ids.zip(entries) - session_ids_and_entries.reject { |_session_id, entry| entry }.each do |session_id, _entry| - redis.srem(lookup_key_name(user.id), session_id) + redis.pipelined do + session_ids_and_entries.reject { |_session_id, entry| entry }.each do |session_id, _entry| + redis.srem(lookup_key_name(user.id), session_id) + end end entries.compact diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb index 5eb535cab58..08e52f32bb3 100644 --- a/app/models/clusters/applications/prometheus.rb +++ b/app/models/clusters/applications/prometheus.rb @@ -83,7 +83,7 @@ module Clusters # ensures headers containing auth data are appended to original k8s client options options = kube_client.rest_client.options.merge(headers: kube_client.headers) - RestClient::Resource.new(proxy_url, options) + Gitlab::PrometheusClient.new(proxy_url, options) rescue Kubeclient::HttpError # If users have mistakenly set parameters or removed the depended clusters, # `proxy_url` could raise an exception because gitlab can not communicate with the cluster. diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 8bb44b0ce40..97d39491b73 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -53,6 +53,7 @@ module Clusters validates :name, cluster_name: true validates :cluster_type, presence: true validates :domain, allow_blank: true, hostname: { allow_numeric_hostname: true } + validates :namespace_per_environment, inclusion: { in: [true, false] } validate :restrict_modification, on: :update validate :no_groups, unless: :group_type? @@ -100,16 +101,6 @@ module Clusters scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) } - scope :with_knative_installed, -> { joins(:application_knative).merge(Clusters::Applications::Knative.available) } - - scope :preload_knative, -> { - preload( - :kubernetes_namespaces, - :platform_kubernetes, - :application_knative - ) - } - def self.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: :asc) return [] if clusterable.is_a?(Instance) @@ -177,36 +168,15 @@ module Clusters platform_kubernetes.kubeclient if kubernetes? end - ## - # This is subtly different to #find_or_initialize_kubernetes_namespace_for_project - # below because it will ignore any namespaces that have not got a service account - # token. This provides a guarantee that any namespace selected here can be used - # for cluster operations - a namespace needs to have a service account configured - # before it it can be used. - # - # This is used for selecting a namespace to use when querying a cluster, or - # generating variables to pass to CI. - def kubernetes_namespace_for(project) - find_or_initialize_kubernetes_namespace_for_project( - project, scope: kubernetes_namespaces.has_service_account_token - ).namespace - end - - ## - # This is subtly different to #kubernetes_namespace_for because it will include - # namespaces that have yet to receive a service account token. This allows - # the namespace configuration process to be repeatable - if a namespace has - # already been created without a token we don't need to create another - # record entirely, just set the token on the pre-existing namespace. - # - # This is used for configuring cluster namespaces. - def find_or_initialize_kubernetes_namespace_for_project(project, scope: kubernetes_namespaces) - attributes = { project: project } - attributes[:cluster_project] = cluster_project if project_type? + def kubernetes_namespace_for(environment) + project = environment.project + persisted_namespace = Clusters::KubernetesNamespaceFinder.new( + self, + project: project, + environment_slug: environment.slug + ).execute - scope.find_or_initialize_by(attributes).tap do |namespace| - namespace.set_defaults - end + persisted_namespace&.namespace || Gitlab::Kubernetes::DefaultNamespace.new(self, project: project).from_environment_slug(environment.slug) end def allow_user_defined_namespace? @@ -225,10 +195,6 @@ module Clusters end end - def knative_services_finder(project) - @knative_services_finder ||= KnativeServicesFinder.new(self, project) - end - private def instance_domain diff --git a/app/models/clusters/kubernetes_namespace.rb b/app/models/clusters/kubernetes_namespace.rb index b0c4900546e..69a2b99fcb6 100644 --- a/app/models/clusters/kubernetes_namespace.rb +++ b/app/models/clusters/kubernetes_namespace.rb @@ -9,12 +9,12 @@ module Clusters belongs_to :cluster_project, class_name: 'Clusters::Project' belongs_to :cluster, class_name: 'Clusters::Cluster' belongs_to :project, class_name: '::Project' + belongs_to :environment, optional: true has_one :platform_kubernetes, through: :cluster - before_validation :set_defaults - validates :namespace, presence: true validates :namespace, uniqueness: { scope: :cluster_id } + validates :environment_id, uniqueness: { scope: [:cluster_id, :project_id] }, allow_nil: true validates :service_account_name, presence: true @@ -27,6 +27,7 @@ module Clusters algorithm: 'aes-256-cbc' scope :has_service_account_token, -> { where.not(encrypted_service_account_token: nil) } + scope :with_environment_slug, -> (slug) { joins(:environment).where(environments: { slug: slug }) } def token_name "#{namespace}-token" @@ -42,34 +43,8 @@ module Clusters end end - def set_defaults - self.namespace ||= default_platform_kubernetes_namespace - self.namespace ||= default_project_namespace - self.service_account_name ||= default_service_account_name - end - private - def default_service_account_name - return unless namespace - - "#{namespace}-service-account" - end - - def default_platform_kubernetes_namespace - platform_kubernetes&.namespace.presence - end - - def default_project_namespace - Gitlab::NamespaceSanitizer.sanitize(project_slug) if project_slug - end - - def project_slug - return unless project - - "#{project.path}-#{project.id}".downcase - end - def kubeconfig to_kubeconfig( url: api_url, diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index 9296c28776b..37614fbe3ca 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -51,11 +51,6 @@ module Clusters delegate :provided_by_user?, to: :cluster, allow_nil: true delegate :allow_user_defined_namespace?, to: :cluster, allow_nil: true - # This is just to maintain compatibility with KubernetesService, which - # will be removed in https://gitlab.com/gitlab-org/gitlab-ce/issues/39217. - # It can be removed once KubernetesService is gone. - delegate :kubernetes_namespace_for, to: :cluster, allow_nil: true - alias_method :active?, :enabled? enum_with_nil authorization_type: { @@ -66,7 +61,7 @@ module Clusters default_value_for :authorization_type, :rbac - def predefined_variables(project:) + def predefined_variables(project:, environment_name:) Gitlab::Ci::Variables::Collection.new.tap do |variables| variables.append(key: 'KUBE_URL', value: api_url) @@ -77,15 +72,14 @@ module Clusters end if !cluster.managed? - project_namespace = namespace.presence || "#{project.path}-#{project.id}".downcase + namespace = Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: project).from_environment_name(environment_name) variables - .append(key: 'KUBE_URL', value: api_url) .append(key: 'KUBE_TOKEN', value: token, public: false, masked: true) - .append(key: 'KUBE_NAMESPACE', value: project_namespace) - .append(key: 'KUBECONFIG', value: kubeconfig(project_namespace), public: false, file: true) + .append(key: 'KUBE_NAMESPACE', value: namespace) + .append(key: 'KUBECONFIG', value: kubeconfig(namespace), public: false, file: true) - elsif kubernetes_namespace = cluster.kubernetes_namespaces.has_service_account_token.find_by(project: project) + elsif kubernetes_namespace = find_persisted_namespace(project, environment_name: environment_name) variables.concat(kubernetes_namespace.predefined_variables) end @@ -111,6 +105,22 @@ module Clusters private + ## + # Environment slug can be predicted given an environment + # name, so even if the environment isn't persisted yet we + # still know what to look for. + def environment_slug(name) + Gitlab::Slug::Environment.new(name).generate + end + + def find_persisted_namespace(project, environment_name:) + Clusters::KubernetesNamespaceFinder.new( + cluster, + project: project, + environment_slug: environment_slug(environment_name) + ).execute + end + def kubeconfig(namespace) to_kubeconfig( url: api_url, diff --git a/app/models/concerns/maskable.rb b/app/models/concerns/maskable.rb index e0f2c41b836..d70e47bc4ff 100644 --- a/app/models/concerns/maskable.rb +++ b/app/models/concerns/maskable.rb @@ -7,9 +7,10 @@ module Maskable # * No escape characters # * No variables # * No spaces - # * Minimal length of 8 characters from the Base64 alphabets (RFC4648) + # * Minimal length of 8 characters + # * Characters must be from the Base64 alphabet (RFC4648) with the addition of @ and : # * Absolutely no fun is allowed - REGEX = /\A[a-zA-Z0-9_+=\/-]{8,}\z/.freeze + REGEX = /\A[a-zA-Z0-9_+=\/@:-]{8,}\z/.freeze included do validates :masked, inclusion: { in: [true, false] } diff --git a/app/models/concerns/prometheus_adapter.rb b/app/models/concerns/prometheus_adapter.rb index c2542dbe743..9ac4722c6b1 100644 --- a/app/models/concerns/prometheus_adapter.rb +++ b/app/models/concerns/prometheus_adapter.rb @@ -14,10 +14,6 @@ module PrometheusAdapter raise NotImplementedError end - def prometheus_client_wrapper - Gitlab::PrometheusClient.new(prometheus_client) - end - def can_query? prometheus_client.present? end @@ -35,7 +31,7 @@ module PrometheusAdapter def calculate_reactive_cache(query_class_name, *args) return unless prometheus_client - data = Object.const_get(query_class_name, false).new(prometheus_client_wrapper).query(*args) + data = Object.const_get(query_class_name, false).new(prometheus_client).query(*args) { success: true, data: data, diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb index db501b4b506..0bd90bd28e3 100644 --- a/app/models/deploy_key.rb +++ b/app/models/deploy_key.rb @@ -2,12 +2,14 @@ class DeployKey < Key include IgnorableColumn + include FromUnion has_many :deploy_keys_projects, inverse_of: :deploy_key, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :projects, through: :deploy_keys_projects scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) } scope :are_public, -> { where(public: true) } + scope :with_projects, -> { includes(deploy_keys_projects: { project: [:route, :namespace] }) } ignore_column :can_push @@ -22,7 +24,7 @@ class DeployKey < Key end def almost_orphaned? - self.deploy_keys_projects.length == 1 + self.deploy_keys_projects.count == 1 end def destroyed_when_orphaned? @@ -46,6 +48,6 @@ class DeployKey < Key end def projects_with_write_access - Project.preload(:route).where(id: deploy_keys_projects.with_write_access.select(:project_id)) + Project.with_route.where(id: deploy_keys_projects.with_write_access.select(:project_id)) end end diff --git a/app/models/deploy_keys_project.rb b/app/models/deploy_keys_project.rb index 15906ed8e06..40c66d5bc4c 100644 --- a/app/models/deploy_keys_project.rb +++ b/app/models/deploy_keys_project.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true class DeployKeysProject < ApplicationRecord - belongs_to :project + belongs_to :project, inverse_of: :deploy_keys_projects belongs_to :deploy_key, inverse_of: :deploy_keys_projects - scope :without_project_deleted, -> { joins(:project).where(projects: { pending_delete: false }) } scope :in_project, ->(project) { where(project: project) } scope :with_write_access, -> { where(can_push: true) } diff --git a/app/models/environment.rb b/app/models/environment.rb index 513427ac2c5..1b53c4b45f9 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -48,6 +48,7 @@ class Environment < ApplicationRecord end scope :in_review_folder, -> { where(environment_type: "review") } scope :for_name, -> (name) { where(name: name) } + scope :preload_cluster, -> { preload(last_deployment: :cluster) } ## # Search environments which have names like the given query. @@ -170,7 +171,7 @@ class Environment < ApplicationRecord def deployment_namespace strong_memoize(:kubernetes_namespace) do - deployment_platform&.kubernetes_namespace_for(project) + deployment_platform.cluster.kubernetes_namespace_for(self) if deployment_platform end end @@ -233,6 +234,12 @@ class Environment < ApplicationRecord end end + def knative_services_finder + if last_deployment&.cluster + Clusters::KnativeServicesFinder.new(last_deployment.cluster, self) + end + end + private def generate_slug diff --git a/app/models/list.rb b/app/models/list.rb index d28a9bda82d..ccadd39bda2 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -3,10 +3,11 @@ class List < ApplicationRecord belongs_to :board belongs_to :label + include Importable enum list_type: { backlog: 0, label: 1, closed: 2, assignee: 3, milestone: 4 } - validates :board, :list_type, presence: true + validates :board, :list_type, presence: true, unless: :importing? validates :label, :position, presence: true, if: :label? validates :label_id, uniqueness: { scope: :board_id }, if: :label? validates :position, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, if: :movable? diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index f45bd0e03de..2c9dbf2585c 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -196,6 +196,12 @@ class MergeRequestDiff < ApplicationRecord real_size.presence || raw_diffs.size end + def lines_count + strong_memoize(:lines_count) do + diffs.diff_files.sum(&:line_count) + end + end + def raw_diffs(options = {}) if options[:ignore_whitespace_change] @diffs_no_whitespace ||= compare.diffs(options) diff --git a/app/models/project.rb b/app/models/project.rb index 8f234fba04f..960795b73cb 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -214,7 +214,7 @@ class Project < ApplicationRecord as: :source, class_name: 'ProjectMember', dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent has_many :members_and_requesters, as: :source, class_name: 'ProjectMember' - has_many :deploy_keys_projects + has_many :deploy_keys_projects, inverse_of: :project has_many :deploy_keys, through: :deploy_keys_projects has_many :users_star_projects has_many :starrers, through: :users_star_projects, source: :user @@ -1487,6 +1487,9 @@ class Project < ApplicationRecord end def pipeline_for(ref, sha = nil, id = nil) + sha ||= commit(ref).try(:sha) + return unless sha + if id.present? pipelines_for(ref, sha).find_by(id: id) else @@ -1494,11 +1497,7 @@ class Project < ApplicationRecord end end - def pipelines_for(ref, sha = nil) - sha ||= commit(ref).try(:sha) - - return unless sha - + def pipelines_for(ref, sha) ci_pipelines.order(id: :desc).where(sha: sha, ref: ref) end @@ -1856,8 +1855,12 @@ class Project < ApplicationRecord end end - def deployment_variables(environment: nil) - deployment_platform(environment: environment)&.predefined_variables(project: self) || [] + def deployment_variables(environment:) + platform = deployment_platform(environment: environment) + + return [] unless platform.present? + + platform.predefined_variables(project: self, environment_name: environment) end def auto_devops_variables diff --git a/app/models/project_services/mock_deployment_service.rb b/app/models/project_services/mock_deployment_service.rb index 1103cb11e73..6f2b0f7747f 100644 --- a/app/models/project_services/mock_deployment_service.rb +++ b/app/models/project_services/mock_deployment_service.rb @@ -24,7 +24,7 @@ class MockDeploymentService < Service %w() end - def predefined_variables(project:) + def predefined_variables(project:, environment_name:) [] end diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb index c68a9d923c8..6eff2ea2e3a 100644 --- a/app/models/project_services/prometheus_service.rb +++ b/app/models/project_services/prometheus_service.rb @@ -63,15 +63,16 @@ class PrometheusService < MonitoringService # Check we can connect to the Prometheus API def test(*args) - Gitlab::PrometheusClient.new(prometheus_client).ping - + prometheus_client.ping { success: true, result: 'Checked API endpoint' } rescue Gitlab::PrometheusClient::Error => err { success: false, result: err } end def prometheus_client - RestClient::Resource.new(api_url, max_redirects: 0) if should_return_client? + return unless should_return_client? + + Gitlab::PrometheusClient.new(api_url) end def prometheus_available? @@ -84,7 +85,7 @@ class PrometheusService < MonitoringService private def should_return_client? - api_url && manual_configuration? && active? && valid? + api_url.present? && manual_configuration? && active? && valid? end def synchronize_service_state diff --git a/app/models/user.rb b/app/models/user.rb index b439d1c0c16..4630552e02e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -933,7 +933,7 @@ class User < ApplicationRecord end def project_deploy_keys - DeployKey.unscoped.in_projects(authorized_projects.pluck(:id)).distinct(:id) + DeployKey.in_projects(authorized_projects.select(:id)).distinct(:id) end def highest_role @@ -941,11 +941,10 @@ class User < ApplicationRecord end def accessible_deploy_keys - @accessible_deploy_keys ||= begin - key_ids = project_deploy_keys.pluck(:id) - key_ids.push(*DeployKey.are_public.pluck(:id)) - DeployKey.where(id: key_ids) - end + DeployKey.from_union([ + DeployKey.where(id: project_deploy_keys.select(:deploy_key_id)), + DeployKey.are_public + ]) end def created_by diff --git a/app/presenters/blob_presenter.rb b/app/presenters/blob_presenter.rb index 2cf3278d240..f85c1a237a6 100644 --- a/app/presenters/blob_presenter.rb +++ b/app/presenters/blob_presenter.rb @@ -3,12 +3,13 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated presents :blob - def highlight(plain: nil) + def highlight(since: nil, to: nil, plain: nil) load_all_blob_data Gitlab::Highlight.highlight( blob.path, - blob.data, + limited_blob_data(since: since, to: to), + since: since, language: blob.language_from_gitattributes, plain: plain ) @@ -23,4 +24,18 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated def load_all_blob_data blob.load_all_data! if blob.respond_to?(:load_all_data!) end + + def limited_blob_data(since: nil, to: nil) + return blob.data if since.blank? || to.blank? + + limited_blob_lines(since, to).join + end + + def limited_blob_lines(since, to) + all_lines[since - 1..to - 1] + end + + def all_lines + @all_lines ||= blob.data.lines + end end diff --git a/app/presenters/blobs/unfold_presenter.rb b/app/presenters/blobs/unfold_presenter.rb index 21a1e1309e0..f4672d22fc9 100644 --- a/app/presenters/blobs/unfold_presenter.rb +++ b/app/presenters/blobs/unfold_presenter.rb @@ -21,20 +21,19 @@ module Blobs load_all_blob_data @subject = blob - @all_lines = blob.data.lines super(params) if full? - self.attributes = { since: 1, to: @all_lines.size, bottom: false, unfold: false, offset: 0, indent: 0 } + self.attributes = { since: 1, to: all_lines.size, bottom: false, unfold: false, offset: 0, indent: 0 } end end # Returns an array of Gitlab::Diff::Line with match line added def diff_lines - diff_lines = lines.map.with_index do |line, index| - full_line = limited_blob_lines[index].delete("\n") + diff_lines = limited_blob_lines(since, to).map.with_index do |line, index| + full_line = line.delete("\n") - Gitlab::Diff::Line.new(full_line, nil, nil, nil, nil, rich_text: line) + Gitlab::Diff::Line.new(full_line, nil, nil, nil, nil, rich_text: lines[index]) end add_match_line(diff_lines) @@ -43,7 +42,7 @@ module Blobs end def lines - @lines ||= limit(highlight.lines).map(&:html_safe) + @lines ||= highlight(since: since, to: to).lines.map(&:html_safe) end def match_line_text @@ -59,7 +58,7 @@ module Blobs def add_match_line(diff_lines) return unless unfold? - if bottom? && to < @all_lines.size + if bottom? && to < all_lines.size old_pos = to - offset new_pos = to elsif since != 1 @@ -73,15 +72,5 @@ module Blobs bottom? ? diff_lines.push(match_line) : diff_lines.unshift(match_line) end - - def limited_blob_lines - @limited_blob_lines ||= limit(@all_lines) - end - - def limit(lines) - return lines if full? - - lines[since - 1..to - 1] - end end end diff --git a/app/presenters/projects/settings/deploy_keys_presenter.rb b/app/presenters/projects/settings/deploy_keys_presenter.rb index 85518c9a3a4..6f8c4e1f902 100644 --- a/app/presenters/projects/settings/deploy_keys_presenter.rb +++ b/app/presenters/projects/settings/deploy_keys_presenter.rb @@ -12,48 +12,38 @@ module Projects @key ||= DeployKey.new.tap { |dk| dk.deploy_keys_projects.build } end - # rubocop: disable CodeReuse/ActiveRecord def enabled_keys - @enabled_keys ||= project.deploy_keys.includes(:projects) - end - # rubocop: enable CodeReuse/ActiveRecord - - def any_keys_enabled? - enabled_keys.any? + project.deploy_keys end def available_keys - @available_keys ||= current_user.accessible_deploy_keys - enabled_keys + current_user + .accessible_deploy_keys + .id_not_in(enabled_keys.select(:id)) + .with_projects end - # rubocop: disable CodeReuse/ActiveRecord def available_project_keys - @available_project_keys ||= current_user.project_deploy_keys.includes(:projects) - enabled_keys - end - # rubocop: enable CodeReuse/ActiveRecord - - def key_available?(deploy_key) - available_keys.include?(deploy_key) + current_user + .project_deploy_keys + .id_not_in(enabled_keys.select(:id)) + .with_projects end - # rubocop: disable CodeReuse/ActiveRecord def available_public_keys - return @available_public_keys if defined?(@available_public_keys) - - @available_public_keys ||= DeployKey.are_public.includes(:projects) - enabled_keys - - # Public keys that are already used by another accessible project are already - # in @available_project_keys. - @available_public_keys -= available_project_keys + DeployKey + .are_public + .id_not_in(enabled_keys.select(:id)) + .id_not_in(available_project_keys.select(:id)) + .with_projects end - # rubocop: enable CodeReuse/ActiveRecord def as_json serializer = DeployKeySerializer.new # rubocop: disable CodeReuse/Serializer opts = { user: current_user } { - enabled_keys: serializer.represent(enabled_keys, opts), + enabled_keys: serializer.represent(enabled_keys.with_projects, opts), available_project_keys: serializer.represent(available_project_keys, opts), public_keys: serializer.represent(available_public_keys, opts) } diff --git a/app/serializers/deploy_key_entity.rb b/app/serializers/deploy_key_entity.rb index 54bf030aba1..e47d6454780 100644 --- a/app/serializers/deploy_key_entity.rb +++ b/app/serializers/deploy_key_entity.rb @@ -10,9 +10,10 @@ class DeployKeyEntity < Grape::Entity expose :created_at expose :updated_at expose :deploy_keys_projects, using: DeployKeysProjectEntity do |deploy_key| - deploy_key.deploy_keys_projects - .without_project_deleted - .select { |deploy_key_project| Ability.allowed?(options[:user], :read_project, deploy_key_project.project) } + deploy_key.deploy_keys_projects.select do |deploy_key_project| + !deploy_key_project.project&.pending_delete? && + Ability.allowed?(options[:user], :read_project, deploy_key_project.project) + end end expose :can_edit diff --git a/app/services/clusters/build_kubernetes_namespace_service.rb b/app/services/clusters/build_kubernetes_namespace_service.rb new file mode 100644 index 00000000000..2574f77bbf9 --- /dev/null +++ b/app/services/clusters/build_kubernetes_namespace_service.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Clusters + class BuildKubernetesNamespaceService + attr_reader :cluster, :environment + + def initialize(cluster, environment:) + @cluster = cluster + @environment = environment + end + + def execute + cluster.kubernetes_namespaces.build(attributes) + end + + private + + def attributes + attributes = { + project: environment.project, + namespace: namespace, + service_account_name: "#{namespace}-service-account" + } + + attributes[:cluster_project] = cluster.cluster_project if cluster.project_type? + attributes[:environment] = environment if cluster.namespace_per_environment? + + attributes + end + + def namespace + Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: environment.project).from_environment_slug(environment.slug) + end + end +end diff --git a/app/services/clusters/create_service.rb b/app/services/clusters/create_service.rb index 5fb5e15c32d..e5a5b73321a 100644 --- a/app/services/clusters/create_service.rb +++ b/app/services/clusters/create_service.rb @@ -11,7 +11,8 @@ module Clusters def execute(access_token: nil) raise ArgumentError, 'Unknown clusterable provided' unless clusterable - cluster_params = params.merge(user: current_user).merge(clusterable_params) + cluster_params = params.merge(global_params).merge(clusterable_params) + cluster_params[:provider_gcp_attributes].try do |provider| provider[:access_token] = access_token end @@ -35,6 +36,10 @@ module Clusters @clusterable ||= params.delete(:clusterable) end + def global_params + { user: current_user, namespace_per_environment: Feature.enabled?(:kubernetes_namespace_per_environment, default_enabled: true) } + end + def clusterable_params case clusterable when ::Project diff --git a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb index 806f320381d..c45dac7b273 100644 --- a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb +++ b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb @@ -11,7 +11,6 @@ module Clusters end def execute - configure_kubernetes_namespace create_project_service_account configure_kubernetes_token @@ -22,10 +21,6 @@ module Clusters attr_reader :cluster, :kubernetes_namespace, :platform - def configure_kubernetes_namespace - kubernetes_namespace.set_defaults - end - def create_project_service_account Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService.namespace_creator( platform.kubeclient, diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index a1279bfb3a3..5893b8eedff 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -173,6 +173,7 @@ module Projects end def remove_registry_tags + return true unless Gitlab.config.registry.enabled return false unless remove_legacy_registry_tags project.container_repositories.find_each do |container_repository| diff --git a/app/services/prometheus/proxy_service.rb b/app/services/prometheus/proxy_service.rb index c5d2b84878b..a62eb76b8ce 100644 --- a/app/services/prometheus/proxy_service.rb +++ b/app/services/prometheus/proxy_service.rb @@ -98,7 +98,7 @@ module Prometheus end def prometheus_client_wrapper - prometheus_adapter&.prometheus_client_wrapper + prometheus_adapter&.prometheus_client end def can_query? diff --git a/app/views/layouts/_google_analytics.html.haml b/app/views/layouts/_google_analytics.html.haml index 98ea96b0b77..e8a5359e791 100644 --- a/app/views/layouts/_google_analytics.html.haml +++ b/app/views/layouts/_google_analytics.html.haml @@ -1,11 +1,11 @@ --# haml-lint:disable InlineJavaScript -:javascript - var _gaq = _gaq || []; - _gaq.push(['_setAccount', '#{extra_config.google_analytics_id}']); - _gaq.push(['_trackPageview']); += javascript_tag nonce: true do + :plain + var _gaq = _gaq || []; + _gaq.push(['_setAccount', '#{extra_config.google_analytics_id}']); + _gaq.push(['_trackPageview']); - (function() { - var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; - ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; - var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); - })(); + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index ac774803f95..271b73326fa 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -40,7 +40,7 @@ = stylesheet_link_tag "highlight/themes/#{user_color_scheme}", media: "all" - = Gon::Base.render_data + = Gon::Base.render_data(nonce: content_security_policy_nonce) - if content_for?(:library_javascripts) = yield :library_javascripts @@ -56,6 +56,7 @@ = yield :project_javascripts = csrf_meta_tags + = csp_meta_tag - unless browser.safari? %meta{ name: 'referrer', content: 'origin-when-cross-origin' } diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml index 240e03a5d53..82ec92988eb 100644 --- a/app/views/layouts/_init_auto_complete.html.haml +++ b/app/views/layouts/_init_auto_complete.html.haml @@ -4,8 +4,8 @@ - datasources = autocomplete_data_sources(object, noteable_type) - if object - -# haml-lint:disable InlineJavaScript - :javascript - gl = window.gl || {}; - gl.GfmAutoComplete = gl.GfmAutoComplete || {}; - gl.GfmAutoComplete.dataSources = #{datasources.to_json}; + = javascript_tag nonce: true do + :plain + gl = window.gl || {}; + gl.GfmAutoComplete = gl.GfmAutoComplete || {}; + gl.GfmAutoComplete.dataSources = #{datasources.to_json}; diff --git a/app/views/layouts/_init_client_detection_flags.html.haml b/app/views/layouts/_init_client_detection_flags.html.haml index c729f8aa696..6537b86085f 100644 --- a/app/views/layouts/_init_client_detection_flags.html.haml +++ b/app/views/layouts/_init_client_detection_flags.html.haml @@ -1,7 +1,7 @@ - client = client_js_flags - if client - -# haml-lint:disable InlineJavaScript - :javascript - gl = window.gl || {}; - gl.client = #{client.to_json}; + = javascript_tag nonce: true do + :plain + gl = window.gl || {}; + gl.client = #{client.to_json}; diff --git a/app/views/layouts/_piwik.html.haml b/app/views/layouts/_piwik.html.haml index 473b14ce626..2cb2e23433d 100644 --- a/app/views/layouts/_piwik.html.haml +++ b/app/views/layouts/_piwik.html.haml @@ -1,15 +1,15 @@ <!-- Piwik --> --# haml-lint:disable InlineJavaScript -:javascript - var _paq = _paq || []; - _paq.push(['trackPageView']); - _paq.push(['enableLinkTracking']); - (function() { - var u="//#{extra_config.piwik_url}/"; - _paq.push(['setTrackerUrl', u+'piwik.php']); - _paq.push(['setSiteId', "#{extra_config.piwik_site_id}"]); - var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; - g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); - })(); -<noscript><p><img src="//#{extra_config.piwik_url}/piwik.php?idsite=#{extra_config.piwik_site_id}" style="border:0;" alt="" /></p></noscript> -<!-- End Piwik Code --> += javascript_tag nonce: true do + :plain + var _paq = _paq || []; + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); + (function() { + var u="//#{extra_config.piwik_url}/"; + _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setSiteId', "#{extra_config.piwik_site_id}"]); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + })(); + <noscript><p><img src="//#{extra_config.piwik_url}/piwik.php?idsite=#{extra_config.piwik_site_id}" style="border:0;" alt="" /></p></noscript> + <!-- End Piwik Code --> diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml index 06069a72951..74484005b48 100644 --- a/app/views/layouts/errors.html.haml +++ b/app/views/layouts/errors.html.haml @@ -8,12 +8,12 @@ %body .page-container = yield - -# haml-lint:disable InlineJavaScript - :javascript - (function(){ - var goBackElement = document.querySelector('.js-go-back'); + = javascript_tag nonce: true do + :plain + (function(){ + var goBackElement = document.querySelector('.js-go-back'); - if (goBackElement && history.length > 1) { - goBackElement.style.display = 'block'; - } - }()); + if (goBackElement && history.length > 1) { + goBackElement.style.display = 'block'; + } + }()); diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 1d40b78fa83..49de821f1c2 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -6,8 +6,8 @@ - content_for :page_specific_javascripts do - if current_user - -# haml-lint:disable InlineJavaScript - :javascript - window.uploads_path = "#{group_uploads_path(@group)}"; + = javascript_tag nonce: true do + :plain + window.uploads_path = "#{group_uploads_path(@group)}"; = render template: "layouts/application" diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index cbe713b7468..ff0c5b241b2 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -32,6 +32,8 @@ = link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets qa-snippets-link' do = _('Snippets') + = render_if_exists 'layouts/nav/sidebar/analytics_link' + - if any_dashboard_nav_link?([:groups, :milestones, :activity, :snippets]) %li.header-more.dropdown.d-xl-none{ class: ('d-lg-none' unless has_extra_nav_icons?) } %a{ href: "#", data: { toggle: "dropdown" } } @@ -53,6 +55,9 @@ = nav_link(controller: 'dashboard/snippets') do = link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets' do = _('Snippets') + + = render_if_exists 'layouts/nav/sidebar/analytics_more_link' + %li.dropdown.d-lg-none = render_if_exists 'dashboard/operations/nav_link_list' - if can?(current_user, :read_instance_statistics) diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml index 6b51483810e..b8ef38272fc 100644 --- a/app/views/layouts/project.html.haml +++ b/app/views/layouts/project.html.haml @@ -7,8 +7,8 @@ - content_for :project_javascripts do - project = @target_project || @project - if current_user - -# haml-lint:disable InlineJavaScript - :javascript - window.uploads_path = "#{project_uploads_path(project)}"; + = javascript_tag nonce: true do + :plain + window.uploads_path = "#{project_uploads_path(project)}"; = render template: "layouts/application" diff --git a/app/views/layouts/snippets.html.haml b/app/views/layouts/snippets.html.haml index 841b2a5e79c..cde2b467392 100644 --- a/app/views/layouts/snippets.html.haml +++ b/app/views/layouts/snippets.html.haml @@ -3,8 +3,8 @@ - content_for :page_specific_javascripts do - if snippets_upload_path - -# haml-lint:disable InlineJavaScript - :javascript - window.uploads_path = "#{snippets_upload_path}"; + = javascript_tag nonce: true do + :plain + window.uploads_path = "#{snippets_upload_path}"; = render template: "layouts/application" diff --git a/app/views/projects/_export.html.haml b/app/views/projects/_export.html.haml index 1056977886a..e42772c2dd9 100644 --- a/app/views/projects/_export.html.haml +++ b/app/views/projects/_export.html.haml @@ -15,6 +15,7 @@ %li= _('Project configuration, including services') %li= _('Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities') %li= _('LFS objects') + %li= _('Issue Boards') %p= _('The following items will NOT be exported:') %ul %li= _('Job traces and artifacts') diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml index 2c5c5141bf0..af3bd8dcd69 100644 --- a/app/views/projects/merge_requests/show.html.haml +++ b/app/views/projects/merge_requests/show.html.haml @@ -16,13 +16,13 @@ - if @merge_request.source_branch_exists? = render "projects/merge_requests/how_to_merge" - -# haml-lint:disable InlineJavaScript - :javascript - window.gl = window.gl || {}; - window.gl.mrWidgetData = #{serialize_issuable(@merge_request, serializer: 'widget', issues_links: true)} + = javascript_tag nonce: true do + :plain + window.gl = window.gl || {}; + window.gl.mrWidgetData = #{serialize_issuable(@merge_request, serializer: 'widget', issues_links: true)} - window.gl.mrWidgetData.squash_before_merge_help_path = '#{help_page_path("user/project/merge_requests/squash_and_merge")}'; - window.gl.mrWidgetData.troubleshooting_docs_path = '#{help_page_path('user/project/merge_requests/index.md', anchor: 'troubleshooting')}'; + window.gl.mrWidgetData.squash_before_merge_help_path = '#{help_page_path("user/project/merge_requests/squash_and_merge")}'; + window.gl.mrWidgetData.troubleshooting_docs_path = '#{help_page_path('user/project/merge_requests/index.md', anchor: 'troubleshooting')}'; #js-vue-mr-widget.mr-widget diff --git a/app/workers/chaos/kill_worker.rb b/app/workers/chaos/kill_worker.rb index bbad53c9b86..80f04db1be4 100644 --- a/app/workers/chaos/kill_worker.rb +++ b/app/workers/chaos/kill_worker.rb @@ -5,6 +5,8 @@ module Chaos include ApplicationWorker include ChaosQueue + sidekiq_options retry: false + def perform Gitlab::Chaos.kill end diff --git a/changelogs/unreleased/31434-make-issue-boards-importable.yml b/changelogs/unreleased/31434-make-issue-boards-importable.yml new file mode 100644 index 00000000000..fd270a236dc --- /dev/null +++ b/changelogs/unreleased/31434-make-issue-boards-importable.yml @@ -0,0 +1,5 @@ +--- +title: Make issue boards importable +merge_request: 31434 +author: Jason Colyer +type: changed diff --git a/changelogs/unreleased/43080-speed-up-deploy-keys.yml b/changelogs/unreleased/43080-speed-up-deploy-keys.yml new file mode 100644 index 00000000000..73c9a9e5f82 --- /dev/null +++ b/changelogs/unreleased/43080-speed-up-deploy-keys.yml @@ -0,0 +1,5 @@ +--- +title: Speed up loading and filtering deploy keys and their projects +merge_request: 31384 +author: +type: performance diff --git a/changelogs/unreleased/52494-separate-namespace-per-project-environment-slug.yml b/changelogs/unreleased/52494-separate-namespace-per-project-environment-slug.yml new file mode 100644 index 00000000000..645c92127a3 --- /dev/null +++ b/changelogs/unreleased/52494-separate-namespace-per-project-environment-slug.yml @@ -0,0 +1,5 @@ +--- +title: Use separate Kubernetes namespaces per environment +merge_request: 30711 +author: +type: added diff --git a/changelogs/unreleased/64608-double-tooltips.yml b/changelogs/unreleased/64608-double-tooltips.yml new file mode 100644 index 00000000000..f6cb1944d26 --- /dev/null +++ b/changelogs/unreleased/64608-double-tooltips.yml @@ -0,0 +1,5 @@ +--- +title: Prevents showing 2 tooltips in pipelines table +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/65152-selective-highlight.yml b/changelogs/unreleased/65152-selective-highlight.yml new file mode 100644 index 00000000000..371dbbd5924 --- /dev/null +++ b/changelogs/unreleased/65152-selective-highlight.yml @@ -0,0 +1,5 @@ +--- +title: Support selective highlighting of lines +merge_request: 31361 +author: +type: performance diff --git a/changelogs/unreleased/65263-manual-action.yml b/changelogs/unreleased/65263-manual-action.yml new file mode 100644 index 00000000000..47b2a2ed329 --- /dev/null +++ b/changelogs/unreleased/65263-manual-action.yml @@ -0,0 +1,5 @@ +--- +title: Hides loading spinner in pipelines actions after request has been fullfiled +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/65660-update-karma-to-4-2-0.yml b/changelogs/unreleased/65660-update-karma-to-4-2-0.yml new file mode 100644 index 00000000000..c0cb40ce169 --- /dev/null +++ b/changelogs/unreleased/65660-update-karma-to-4-2-0.yml @@ -0,0 +1,5 @@ +--- +title: Update karma to 4.2.0 +merge_request: 31495 +author: Takuya Noguchi +type: other diff --git a/changelogs/unreleased/65671-update-mini_magick-to-4-9-5.yml b/changelogs/unreleased/65671-update-mini_magick-to-4-9-5.yml new file mode 100644 index 00000000000..a6f8576ae0b --- /dev/null +++ b/changelogs/unreleased/65671-update-mini_magick-to-4-9-5.yml @@ -0,0 +1,5 @@ +--- +title: Update mini_magick to 4.9.5 +merge_request: 31505 +author: Takuya Noguchi +type: security diff --git a/changelogs/unreleased/khair1-master-patch-79459.yml b/changelogs/unreleased/khair1-master-patch-79459.yml new file mode 100644 index 00000000000..22b0877336d --- /dev/null +++ b/changelogs/unreleased/khair1-master-patch-79459.yml @@ -0,0 +1,5 @@ +--- +title: Update Packer.gitlab-ci.yml to use latest image +merge_request: +author: Kelly Hair +type: other diff --git a/changelogs/unreleased/mc-feature-add-at-colon-variable-masking.yml b/changelogs/unreleased/mc-feature-add-at-colon-variable-masking.yml new file mode 100644 index 00000000000..9b8eff8e043 --- /dev/null +++ b/changelogs/unreleased/mc-feature-add-at-colon-variable-masking.yml @@ -0,0 +1,5 @@ +--- +title: 'Allows masking @ and : characters.' +merge_request: 31065 +author: +type: changed diff --git a/changelogs/unreleased/remove-peek-gc.yml b/changelogs/unreleased/remove-peek-gc.yml new file mode 100644 index 00000000000..9412cd7c9a6 --- /dev/null +++ b/changelogs/unreleased/remove-peek-gc.yml @@ -0,0 +1,5 @@ +--- +title: Remove GC metrics from performance bar +merge_request: +author: +type: removed diff --git a/changelogs/unreleased/sh-disable-registry-delete.yml b/changelogs/unreleased/sh-disable-registry-delete.yml new file mode 100644 index 00000000000..180b983e07c --- /dev/null +++ b/changelogs/unreleased/sh-disable-registry-delete.yml @@ -0,0 +1,5 @@ +--- +title: Don't attempt to contact registry if it is disabled +merge_request: 31553 +author: +type: fixed diff --git a/changelogs/unreleased/sh-support-csp-nonce.yml b/changelogs/unreleased/sh-support-csp-nonce.yml new file mode 100644 index 00000000000..3e6ac1e4a32 --- /dev/null +++ b/changelogs/unreleased/sh-support-csp-nonce.yml @@ -0,0 +1,5 @@ +--- +title: Add support for Content-Security-Policy +merge_request: 31402 +author: +type: added diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 39b719a5978..226f2ec3722 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -47,6 +47,29 @@ production: &base # # relative_url_root: /gitlab + # Content Security Policy + # See https://guides.rubyonrails.org/security.html#content-security-policy + content_security_policy: + enabled: false + report_only: false + directives: + base_uri: + child_src: + connect_src: "'self' http://localhost:3808 ws://localhost:3808 wss://localhost:3000" + default_src: "'self'" + font_src: + form_action: + frame_ancestors: "'self'" + frame_src: "'self' https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com" + img_src: "* data: blob" + manifest_src: + media_src: + object_src: "'self' http://localhost:3808 'unsafe-inline' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://www.gstatic.com/recaptcha/ https://apis.google.com" + script_src: + style_src: "'self' 'unsafe-inline'" + worker_src: "http://localhost:3000 blob:" + report_uri: + # Trusted Proxies # Customize if you have GitLab behind a reverse proxy which is running on a different machine. # Add the IP address for your reverse proxy to the list, otherwise users will appear signed in from that address. diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 659801f787d..828732126b6 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -200,6 +200,7 @@ Settings.gitlab.default_projects_features['visibility_level'] = Settings.__sen Settings.gitlab['domain_whitelist'] ||= [] Settings.gitlab['import_sources'] ||= Gitlab::ImportSources.values Settings.gitlab['trusted_proxies'] ||= [] +Settings.gitlab['content_security_policy'] ||= Gitlab::ContentSecurityPolicy::ConfigLoader.default_settings_hash Settings.gitlab['no_todos_messages'] ||= YAML.load_file(Rails.root.join('config', 'no_todos_messages.yml')) Settings.gitlab['impersonation_enabled'] ||= true if Settings.gitlab['impersonation_enabled'].nil? Settings.gitlab['usage_ping_enabled'] = true if Settings.gitlab['usage_ping_enabled'].nil? diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb new file mode 100644 index 00000000000..608d0401a96 --- /dev/null +++ b/config/initializers/content_security_policy.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +csp_settings = Settings.gitlab.content_security_policy + +if csp_settings['enabled'] + # See https://guides.rubyonrails.org/security.html#content-security-policy + Rails.application.config.content_security_policy do |policy| + directives = csp_settings.fetch('directives', {}) + loader = ::Gitlab::ContentSecurityPolicy::ConfigLoader.new(directives) + loader.load(policy) + end + + Rails.application.config.content_security_policy_report_only = csp_settings['report_only'] + Rails.application.config.content_security_policy_nonce_generator = ->(request) { SecureRandom.base64(16) } +end diff --git a/config/initializers/peek.rb b/config/initializers/peek.rb index b6c7f1ff4fc..f9055285e5c 100644 --- a/config/initializers/peek.rb +++ b/config/initializers/peek.rb @@ -10,9 +10,4 @@ Peek.into Peek::Views::Gitaly Peek.into Peek::Views::RedisDetailed Peek.into Peek::Views::Rugged -# `Peek::Views::GC` is currently disabled in production, as it runs with every request -# even if PerformanceBar is inactive and clears `GC::Profiler` reports we need for metrics. -# Check https://gitlab.com/gitlab-org/gitlab-ce/issues/65455 -Peek.into Peek::Views::GC if Rails.env.development? - Peek.into Peek::Views::Tracing if Labkit::Tracing.tracing_url_enabled? diff --git a/db/migrate/20190627100221_add_mr_productivity_metrics.rb b/db/migrate/20190627100221_add_mr_productivity_metrics.rb new file mode 100644 index 00000000000..b6f1520cb2d --- /dev/null +++ b/db/migrate/20190627100221_add_mr_productivity_metrics.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class AddMrProductivityMetrics < ActiveRecord::Migration[5.1] + DOWNTIME = false + + def change + add_column :merge_request_metrics, :first_comment_at, :datetime_with_timezone + add_column :merge_request_metrics, :first_commit_at, :datetime_with_timezone + add_column :merge_request_metrics, :last_commit_at, :datetime_with_timezone + add_column :merge_request_metrics, :diff_size, :integer + add_column :merge_request_metrics, :modified_paths_size, :integer + add_column :merge_request_metrics, :commits_count, :integer + end +end diff --git a/db/migrate/20190712040400_add_environment_id_to_clusters_kubernetes_namespaces.rb b/db/migrate/20190712040400_add_environment_id_to_clusters_kubernetes_namespaces.rb new file mode 100644 index 00000000000..5ab5a9ba2f8 --- /dev/null +++ b/db/migrate/20190712040400_add_environment_id_to_clusters_kubernetes_namespaces.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class AddEnvironmentIdToClustersKubernetesNamespaces < ActiveRecord::Migration[5.1] + DOWNTIME = false + + def change + add_reference :clusters_kubernetes_namespaces, :environment, + index: true, type: :bigint, foreign_key: { on_delete: :nullify } + end +end diff --git a/db/migrate/20190712040412_index_clusters_kubernetes_namespaces_on_environment_id.rb b/db/migrate/20190712040412_index_clusters_kubernetes_namespaces_on_environment_id.rb new file mode 100644 index 00000000000..23082492091 --- /dev/null +++ b/db/migrate/20190712040412_index_clusters_kubernetes_namespaces_on_environment_id.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class IndexClustersKubernetesNamespacesOnEnvironmentId < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + INDEX_NAME = 'index_kubernetes_namespaces_on_cluster_project_environment_id' + + disable_ddl_transaction! + + def up + add_concurrent_index :clusters_kubernetes_namespaces, [:cluster_id, :project_id, :environment_id], unique: true, name: INDEX_NAME + end + + def down + remove_concurrent_index :clusters_kubernetes_namespaces, name: INDEX_NAME + end +end diff --git a/db/migrate/20190712064021_add_namespace_per_environment_flag_to_clusters.rb b/db/migrate/20190712064021_add_namespace_per_environment_flag_to_clusters.rb new file mode 100644 index 00000000000..4c8a0ab3def --- /dev/null +++ b/db/migrate/20190712064021_add_namespace_per_environment_flag_to_clusters.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddNamespacePerEnvironmentFlagToClusters < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default :clusters, :namespace_per_environment, :boolean, default: false + end + + def down + remove_column :clusters, :namespace_per_environment + end +end diff --git a/db/migrate/20190801193427_rename_application_settings_snowplow_collector_uri_column.rb b/db/migrate/20190801193427_rename_application_settings_snowplow_collector_uri_column.rb new file mode 100644 index 00000000000..a4bd5841a46 --- /dev/null +++ b/db/migrate/20190801193427_rename_application_settings_snowplow_collector_uri_column.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class RenameApplicationSettingsSnowplowCollectorUriColumn < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + rename_column_concurrently :application_settings, :snowplow_collector_uri, :snowplow_collector_hostname + end + + def down + cleanup_concurrent_column_rename :application_settings, :snowplow_collector_hostname, :snowplow_collector_uri + end +end diff --git a/db/post_migrate/20190802091750_cleanup_application_settings_snowplow_collector_uri_rename.rb b/db/post_migrate/20190802091750_cleanup_application_settings_snowplow_collector_uri_rename.rb new file mode 100644 index 00000000000..768ece925c6 --- /dev/null +++ b/db/post_migrate/20190802091750_cleanup_application_settings_snowplow_collector_uri_rename.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class CleanupApplicationSettingsSnowplowCollectorUriRename < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + cleanup_concurrent_column_rename :application_settings, :snowplow_collector_uri, :snowplow_collector_hostname + end + + def down + rename_column_concurrently :application_settings, :snowplow_collector_hostname, :snowplow_collector_uri + end +end diff --git a/db/post_migrate/20190802235445_add_index_on_id_and_type_and_public_to_keys.rb b/db/post_migrate/20190802235445_add_index_on_id_and_type_and_public_to_keys.rb new file mode 100644 index 00000000000..9b4d74b4bea --- /dev/null +++ b/db/post_migrate/20190802235445_add_index_on_id_and_type_and_public_to_keys.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class AddIndexOnIdAndTypeAndPublicToKeys < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + INDEX_NAME = "index_on_deploy_keys_id_and_type_and_public" + + def up + add_concurrent_index(:keys, + [:id, :type], + where: "public = 't'", + unique: true, + name: INDEX_NAME) + end + + def down + remove_concurrent_index_by_name(:keys, INDEX_NAME) + end +end diff --git a/db/schema.rb b/db/schema.rb index f7d0e1a4813..890f4ab4d8a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_08_02_012622) do +ActiveRecord::Schema.define(version: 2019_08_02_235445) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -195,7 +195,6 @@ ActiveRecord::Schema.define(version: 2019_08_02_012622) do t.boolean "pseudonymizer_enabled", default: false, null: false t.boolean "hide_third_party_offers", default: false, null: false t.boolean "snowplow_enabled", default: false, null: false - t.string "snowplow_collector_uri" t.string "snowplow_site_id" t.string "snowplow_cookie_domain" t.boolean "instance_statistics_visibility_private", default: false, null: false @@ -232,6 +231,7 @@ ActiveRecord::Schema.define(version: 2019_08_02_012622) do t.boolean "allow_local_requests_from_web_hooks_and_services", default: false, null: false t.boolean "allow_local_requests_from_system_hooks", default: true, null: false t.bigint "instance_administration_project_id" + t.string "snowplow_collector_hostname" t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id" t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id" t.index ["instance_administration_project_id"], name: "index_applicationsettings_on_instance_administration_project_id" @@ -882,6 +882,7 @@ ActiveRecord::Schema.define(version: 2019_08_02_012622) do t.integer "cluster_type", limit: 2, default: 3, null: false t.string "domain" t.boolean "managed", default: true, null: false + t.boolean "namespace_per_environment", default: false, null: false t.index ["enabled"], name: "index_clusters_on_enabled" t.index ["user_id"], name: "index_clusters_on_user_id" end @@ -986,9 +987,12 @@ ActiveRecord::Schema.define(version: 2019_08_02_012622) do t.string "encrypted_service_account_token_iv" t.string "namespace", null: false t.string "service_account_name" + t.bigint "environment_id" t.index ["cluster_id", "namespace"], name: "kubernetes_namespaces_cluster_and_namespace", unique: true + t.index ["cluster_id", "project_id", "environment_id"], name: "index_kubernetes_namespaces_on_cluster_project_environment_id", unique: true t.index ["cluster_id"], name: "index_clusters_kubernetes_namespaces_on_cluster_id" t.index ["cluster_project_id"], name: "index_clusters_kubernetes_namespaces_on_cluster_project_id" + t.index ["environment_id"], name: "index_clusters_kubernetes_namespaces_on_environment_id" t.index ["project_id"], name: "index_clusters_kubernetes_namespaces_on_project_id" end @@ -1772,6 +1776,7 @@ ActiveRecord::Schema.define(version: 2019_08_02_012622) do t.boolean "public", default: false, null: false t.datetime "last_used_at" t.index ["fingerprint"], name: "index_keys_on_fingerprint", unique: true + t.index ["id", "type"], name: "index_on_deploy_keys_id_and_type_and_public", unique: true, where: "(public = true)" t.index ["user_id"], name: "index_keys_on_user_id" end @@ -1981,6 +1986,12 @@ ActiveRecord::Schema.define(version: 2019_08_02_012622) do t.integer "merged_by_id" t.integer "latest_closed_by_id" t.datetime_with_timezone "latest_closed_at" + t.datetime_with_timezone "first_comment_at" + t.datetime_with_timezone "first_commit_at" + t.datetime_with_timezone "last_commit_at" + t.integer "diff_size" + t.integer "modified_paths_size" + t.integer "commits_count" t.index ["first_deployed_to_production_at"], name: "index_merge_request_metrics_on_first_deployed_to_production_at" t.index ["latest_closed_at"], name: "index_merge_request_metrics_on_latest_closed_at", where: "(latest_closed_at IS NOT NULL)" t.index ["latest_closed_by_id"], name: "index_merge_request_metrics_on_latest_closed_by_id" @@ -3707,6 +3718,7 @@ ActiveRecord::Schema.define(version: 2019_08_02_012622) do add_foreign_key "clusters_applications_runners", "clusters", on_delete: :cascade add_foreign_key "clusters_kubernetes_namespaces", "cluster_projects", on_delete: :nullify add_foreign_key "clusters_kubernetes_namespaces", "clusters", on_delete: :cascade + add_foreign_key "clusters_kubernetes_namespaces", "environments", on_delete: :nullify add_foreign_key "clusters_kubernetes_namespaces", "projects", on_delete: :nullify add_foreign_key "container_repositories", "projects" add_foreign_key "dependency_proxy_blobs", "namespaces", column: "group_id", name: "fk_db58bbc5d7", on_delete: :cascade diff --git a/doc/administration/auth/img/google_secure_ldap_add_step_1.png b/doc/administration/auth/img/google_secure_ldap_add_step_1.png Binary files differindex fd254443d75..bee9c602a14 100644 --- a/doc/administration/auth/img/google_secure_ldap_add_step_1.png +++ b/doc/administration/auth/img/google_secure_ldap_add_step_1.png diff --git a/doc/administration/auth/img/google_secure_ldap_add_step_2.png b/doc/administration/auth/img/google_secure_ldap_add_step_2.png Binary files differindex 611a21ae03c..b127410cb8c 100644 --- a/doc/administration/auth/img/google_secure_ldap_add_step_2.png +++ b/doc/administration/auth/img/google_secure_ldap_add_step_2.png diff --git a/doc/administration/auth/img/google_secure_ldap_client_settings.png b/doc/administration/auth/img/google_secure_ldap_client_settings.png Binary files differindex 3c0b3f3d4bd..868e6645f56 100644 --- a/doc/administration/auth/img/google_secure_ldap_client_settings.png +++ b/doc/administration/auth/img/google_secure_ldap_client_settings.png diff --git a/doc/administration/geo/disaster_recovery/img/checksum-differences-admin-project-page.png b/doc/administration/geo/disaster_recovery/img/checksum-differences-admin-project-page.png Binary files differindex fd51523104b..0a7b841897b 100644 --- a/doc/administration/geo/disaster_recovery/img/checksum-differences-admin-project-page.png +++ b/doc/administration/geo/disaster_recovery/img/checksum-differences-admin-project-page.png diff --git a/doc/administration/geo/disaster_recovery/img/checksum-differences-admin-projects.png b/doc/administration/geo/disaster_recovery/img/checksum-differences-admin-projects.png Binary files differindex b2a6da69d3d..85759d903a4 100644 --- a/doc/administration/geo/disaster_recovery/img/checksum-differences-admin-projects.png +++ b/doc/administration/geo/disaster_recovery/img/checksum-differences-admin-projects.png diff --git a/doc/administration/geo/replication/img/geo_architecture.png b/doc/administration/geo/replication/img/geo_architecture.png Binary files differindex d318cd5d0f4..aac63be41ff 100644 --- a/doc/administration/geo/replication/img/geo_architecture.png +++ b/doc/administration/geo/replication/img/geo_architecture.png diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md index 432056d48c7..150494c47e5 100644 --- a/doc/administration/gitaly/index.md +++ b/doc/administration/gitaly/index.md @@ -36,13 +36,18 @@ installations will be better served with the default configuration used by Omnibus and the GitLab source installation guide. Starting with GitLab 11.4, Gitaly is able to serve all Git requests without -needed a shared NFS mount for Git repository data. +requiring a shared NFS mount for Git repository data. Between 11.4 and 11.8 the exception was the [Elasticsearch indexer](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer). But since 11.8 the indexer uses Gitaly for data access as well. NFS can still be leveraged for redudancy on block level of the Git data. But only has to be mounted on the Gitaly server. +Starting with GitLab 11.8, it is possible to use ElasticSearch in conjunction with +a Gitaly setup that isn't utilising NFS. In order to use ElasticSearch in this +scenario, the [new repository indexer](../../integration/elasticsearch.md#elasticsearch-repository-indexer-beta) +needs to be enabled in your GitLab configuration. + NOTE: **Note:** While Gitaly can be used as a replacement for NFS, it's not recommended to use EFS as it may impact GitLab's performance. Review the [relevant documentation](../high_availability/nfs.md#avoid-using-awss-elastic-file-system-efs) for more details. diff --git a/doc/administration/high_availability/img/fully-distributed.png b/doc/administration/high_availability/img/fully-distributed.png Binary files differindex ad23207134e..c3cd2bf24f0 100644 --- a/doc/administration/high_availability/img/fully-distributed.png +++ b/doc/administration/high_availability/img/fully-distributed.png diff --git a/doc/administration/high_availability/img/horizontal.png b/doc/administration/high_availability/img/horizontal.png Binary files differindex c3bd489d96f..75d08e1097a 100644 --- a/doc/administration/high_availability/img/horizontal.png +++ b/doc/administration/high_availability/img/horizontal.png diff --git a/doc/administration/high_availability/img/hybrid.png b/doc/administration/high_availability/img/hybrid.png Binary files differindex 7d4a56bf0ea..8dd9923e597 100644 --- a/doc/administration/high_availability/img/hybrid.png +++ b/doc/administration/high_availability/img/hybrid.png diff --git a/doc/administration/high_availability/monitoring_node.md b/doc/administration/high_availability/monitoring_node.md index b91a994d01e..b2750603c74 100644 --- a/doc/administration/high_availability/monitoring_node.md +++ b/doc/administration/high_availability/monitoring_node.md @@ -18,7 +18,7 @@ The steps below are the minimum necessary to configure a Monitoring node running Omnibus: 1. SSH into the Monitoring node. -1. [Download/install](https://about.gitlab.com/install) the Omnibus GitLab +1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab package you want using **steps 1 and 2** from the GitLab downloads page. - Do not complete any other steps on the download page. diff --git a/doc/administration/high_availability/nfs.md b/doc/administration/high_availability/nfs.md index 294f0e969d5..274bd32299b 100644 --- a/doc/administration/high_availability/nfs.md +++ b/doc/administration/high_availability/nfs.md @@ -71,6 +71,11 @@ bug](https://bugzilla.redhat.com/show_bug.cgi?id=1552203) that may be fixed in [more recent kernels with this commit](https://github.com/torvalds/linux/commit/95da1b3a5aded124dd1bda1e3cdb876184813140). +NOTE: **Note** Red Hat Enterprise 7 [shipped a kernel +update](https://access.redhat.com/errata/RHSA-2019:2029) on August 6, +2019 that may have resolved this problem. The following instructions may +not be needed if the latest kernel is updated properly. + GitLab recommends all NFS users disable the NFS server delegation feature. To disable NFS server delegations on an Linux NFS server, do the following: diff --git a/doc/administration/img/custom_hooks_error_msg.png b/doc/administration/img/custom_hooks_error_msg.png Binary files differindex 4f25c471908..e7d5c157d08 100644 --- a/doc/administration/img/custom_hooks_error_msg.png +++ b/doc/administration/img/custom_hooks_error_msg.png diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md index 4dd0bbbe937..6778c339922 100644 --- a/doc/administration/monitoring/performance/grafana_configuration.md +++ b/doc/administration/monitoring/performance/grafana_configuration.md @@ -1,6 +1,6 @@ # Grafana Configuration -[Grafana](https://grafana.org/) is a tool that allows you to visualize time +[Grafana](https://grafana.com/) is a tool that allows you to visualize time series metrics through graphs and dashboards. It supports several backend data stores, including InfluxDB. GitLab writes performance data to InfluxDB and Grafana will allow you to query to display useful graphs. diff --git a/doc/administration/monitoring/performance/img/performance_bar.png b/doc/administration/monitoring/performance/img/performance_bar.png Binary files differindex 89b09054d46..d1187fd879a 100644 --- a/doc/administration/monitoring/performance/img/performance_bar.png +++ b/doc/administration/monitoring/performance/img/performance_bar.png diff --git a/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png b/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png Binary files differindex 265178729c4..2c43201cbd0 100644 --- a/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png +++ b/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png diff --git a/doc/administration/monitoring/performance/img/performance_bar_redis_calls.png b/doc/administration/monitoring/performance/img/performance_bar_redis_calls.png Binary files differindex 78dd7594adf..ecb2dffbf8d 100644 --- a/doc/administration/monitoring/performance/img/performance_bar_redis_calls.png +++ b/doc/administration/monitoring/performance/img/performance_bar_redis_calls.png diff --git a/doc/administration/monitoring/performance/img/performance_bar_rugged_calls.png b/doc/administration/monitoring/performance/img/performance_bar_rugged_calls.png Binary files differindex f4068268137..210f80a713d 100644 --- a/doc/administration/monitoring/performance/img/performance_bar_rugged_calls.png +++ b/doc/administration/monitoring/performance/img/performance_bar_rugged_calls.png diff --git a/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png b/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png Binary files differindex dab323eb066..6b571f4e85c 100644 --- a/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png +++ b/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png diff --git a/doc/administration/monitoring/performance/img/request_profile_result.png b/doc/administration/monitoring/performance/img/request_profile_result.png Binary files differindex 3b34f207974..9176a0b49fd 100644 --- a/doc/administration/monitoring/performance/img/request_profile_result.png +++ b/doc/administration/monitoring/performance/img/request_profile_result.png diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md index 2cc78ccc03c..02f4b78bd60 100644 --- a/doc/administration/monitoring/performance/performance_bar.md +++ b/doc/administration/monitoring/performance/performance_bar.md @@ -16,7 +16,6 @@ It allows you to see (from left to right): ![Rugged profiling using the Performance Bar](img/performance_bar_rugged_calls.png) - time taken and number of Redis calls, click through for details of these calls ![Redis profiling using the Performance Bar](img/performance_bar_redis_calls.png) -- time taken and number of Ruby GC calls On the far right is a request selector that allows you to view the same metrics (excluding the page timing and line profiler) for any requests made while the diff --git a/doc/administration/operations/img/sidekiq-cluster.png b/doc/administration/operations/img/sidekiq-cluster.png Binary files differindex 4eb1849010e..3899385eb8f 100644 --- a/doc/administration/operations/img/sidekiq-cluster.png +++ b/doc/administration/operations/img/sidekiq-cluster.png diff --git a/doc/administration/pages/img/lets_encrypt_integration_v12_1.png b/doc/administration/pages/img/lets_encrypt_integration_v12_1.png Binary files differindex 5ab63074e12..0f3ca25ce55 100644 --- a/doc/administration/pages/img/lets_encrypt_integration_v12_1.png +++ b/doc/administration/pages/img/lets_encrypt_integration_v12_1.png diff --git a/doc/administration/troubleshooting/elasticsearch.md b/doc/administration/troubleshooting/elasticsearch.md index d54dd758d29..c4a7ba01fae 100644 --- a/doc/administration/troubleshooting/elasticsearch.md +++ b/doc/administration/troubleshooting/elasticsearch.md @@ -5,17 +5,17 @@ Troubleshooting ElasticSearch requires: - Knowledge of common terms. - Establishing within which category the problem fits. -## Common Terminology +## Common terminology - **Lucene**: A full-text search library written in Java. - **Near Realtime (NRT)**: Refers to the slight latency from the time to index a document to the time when it becomes searchable. -- **Cluster**: A collection of one or more nodes that work together to hold all +- **Cluster**: A collection of one or more nodes that work together to hold all the data, providing indexing and search capabilities. - **Node**: A single server that works as part of a cluster. - **Index**: A collection of documents that have somewhat similar characteristics. - **Document**: A basic unit of information that can be indexed. -- **Shards**: Fully-functional and independent subdivisions of indices. Each shard is actually +- **Shards**: Fully-functional and independent subdivisions of indices. Each shard is actually a Lucene index. - **Replicas**: Failover mechanisms that duplicate indices. @@ -138,7 +138,7 @@ graph TD; F7(Escalate to<br>GitLab support.) ``` -## Troubleshooting Walkthrough +## Troubleshooting walkthrough Most ElasticSearch troubleshooting can be broken down into 4 categories: @@ -150,7 +150,7 @@ Most ElasticSearch troubleshooting can be broken down into 4 categories: Generally speaking, if it does not fall into those four categories, it is either: - Something GitLab support needs to look into. -- Not a true ElasticSearch issue. +- Not a true ElasticSearch issue. Exercise caution. Issues that appear to be ElasticSearch problems can be OS-level issues. @@ -186,12 +186,12 @@ Moving past that, it is best to attempt the same search using the [ElasticSearch If the results: -- Sync up, then there is not a technical "issue" per se. Instead, it might be a problem - with the ElasticSearch filters we are using. This can be complicated, so it is best to - escalate to GitLab support to check these and guide you on the potential on whether or +- Sync up, then there is not a technical "issue" per se. Instead, it might be a problem + with the ElasticSearch filters we are using. This can be complicated, so it is best to + escalate to GitLab support to check these and guide you on the potential on whether or not a feature request is needed. - Do not match up, this indicates a problem with the documents generated from the - project. It is best to re-index that project and proceed with + project. It is best to re-index that project and proceed with [Troubleshooting indexing](#troubleshooting-indexing). ### Troubleshooting indexing @@ -200,13 +200,13 @@ Troubleshooting indexing issues can be tricky. It can pretty quickly go to eithe support or your ElasticSearch admin. The best place to start is to determine if the issue is with creating an empty index. -If it is, check on the ElasticSearch side to determine if the `gitlab-production` (the +If it is, check on the ElasticSearch side to determine if the `gitlab-production` (the name for the GitLab index) exists. If it exists, manually delete it on the ElasticSearch -side and attempt to recreate it from the -[`create_empty_index`](../../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks) +side and attempt to recreate it from the +[`create_empty_index`](../../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks) rake task. -If you still encounter issues, try creating an index manually on the ElasticSearch +If you still encounter issues, try creating an index manually on the ElasticSearch instance. The details of the index aren't important here, as we want to test if indices can be made. If the indices: @@ -317,7 +317,7 @@ dig further into these. Feel free to reach out to GitLab support, but this is likely to be something a skilled ElasticSearch admin has more experience with. -## Common Issues +## Common issues All common issues [should be documented](../../integration/elasticsearch.md#troubleshooting). If not, feel free to update that page with issues you encounter and solutions. diff --git a/doc/api/README.md b/doc/api/README.md index 6cd89e34921..9f23af3f723 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -697,10 +697,10 @@ programming languages. Visit the [GitLab website] for a complete list. ## Rate limits -For administrator documentation on rate limit settings, check out +For administrator documentation on rate limit settings, see [Rate limits](../security/rate_limits.md). To find the settings that are specifically used by GitLab.com, see -[GitLab.com-specific rate limits](../user/gitlab_com/index.md). +[GitLab.com-specific rate limits](../user/gitlab_com/index.md#gitlabcom-specific-rate-limits). [GitLab website]: https://about.gitlab.com/applications/#api-clients "Clients using the GitLab API" [lib-api-url]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/api/api.rb diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md index c211916464a..cc95689a65f 100644 --- a/doc/api/merge_request_approvals.md +++ b/doc/api/merge_request_approvals.md @@ -72,13 +72,14 @@ POST /projects/:id/approvals **Parameters:** -| Attribute | Type | Required | Description | -| ------------------------------------------------ | ------- | -------- | ---------------------------------------------------------- | -| `id` | integer | yes | The ID of a project | -| `approvals_before_merge` | integer | no | How many approvals are required before an MR can be merged | -| `reset_approvals_on_push` | boolean | no | Reset approvals on a new push | -| `disable_overriding_approvers_per_merge_request` | boolean | no | Allow/Disallow overriding approvers per MR | -| `merge_requests_author_approval` | boolean | no | Allow/Disallow authors be able to self approve merge requests | +| Attribute | Type | Required | Description | +| ------------------------------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------- | +| `id` | integer | yes | The ID of a project | +| `approvals_before_merge` | integer | no | How many approvals are required before an MR can be merged | +| `reset_approvals_on_push` | boolean | no | Reset approvals on a new push | +| `disable_overriding_approvers_per_merge_request` | boolean | no | Allow/Disallow overriding approvers per MR | +| `merge_requests_author_approval` | boolean | no | Allow/Disallow authors from self approving merge requests; `true` means authors cannot self approve | +| `merge_requests_disable_committers_approval` | boolean | no | Allow/Disallow committers from self approving merge requests | ```json { @@ -115,7 +116,8 @@ POST /projects/:id/approvals "approvals_before_merge": 2, "reset_approvals_on_push": true, "disable_overriding_approvers_per_merge_request": false, - "merge_requests_author_approval": false + "merge_requests_author_approval": false, + "merge_requests_disable_committers_approval": false } ``` diff --git a/doc/api/releases/img/upcoming_release_v12_1.png b/doc/api/releases/img/upcoming_release_v12_1.png Binary files differindex 8bd8573ce84..cc3070fd19d 100644 --- a/doc/api/releases/img/upcoming_release_v12_1.png +++ b/doc/api/releases/img/upcoming_release_v12_1.png diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md index 278a0d6e934..2cbad5f101c 100644 --- a/doc/ci/docker/using_docker_build.md +++ b/doc/ci/docker/using_docker_build.md @@ -98,9 +98,62 @@ The second approach is to use the special docker-in-docker (dind) (`docker`) and run the job script in context of that image in privileged mode. -NOTE: **Note:** `docker-compose` is not part of docker-in-docker (dind). In case you'd like to use `docker-compose` in your CI builds, please follow the [installation instructions for docker-compose](https://docs.docker.com/compose/install/) provided by docker. +NOTE: **Note:** +`docker-compose` is not part of docker-in-docker (dind). To use `docker-compose` in your +CI builds, follow the `docker-compose` +[installation instructions](https://docs.docker.com/compose/install/). -In order to do that, follow the steps: +DANGER: **Danger:** +By enabling `--docker-privileged`, you are effectively disabling all of +the security mechanisms of containers and exposing your host to privilege +escalation which can lead to container breakout. For more information, check +out the official Docker documentation on +[Runtime privilege and Linux capabilities][docker-cap]. + +Docker-in-Docker works well, and is the recommended configuration, but it is +not without its own challenges: + +- When using docker-in-docker, each job is in a clean environment without the past + history. Concurrent jobs work fine because every build gets it's own + instance of Docker engine so they won't conflict with each other. But this + also means jobs can be slower because there's no caching of layers. +- By default, `docker:dind` uses `--storage-driver vfs` which is the slowest + form offered. To use a different driver, see + [Using the overlayfs driver](#using-the-overlayfs-driver). +- Since the `docker:dind` container and the runner container don't share their + root filesystem, the job's working directory can be used as a mount point for + child containers. For example, if you have files you want to share with a + child container, you may create a subdirectory under `/builds/$CI_PROJECT_PATH` + and use it as your mount point (for a more thorough explanation, check [issue + #41227](https://gitlab.com/gitlab-org/gitlab-ce/issues/41227)): + + ```yaml + variables: + MOUNT_POINT: /builds/$CI_PROJECT_PATH/mnt + + script: + - mkdir -p "$MOUNT_POINT" + - docker run -v "$MOUNT_POINT:/mnt" my-docker-image + ``` + +An example project using this approach can be found here: <https://gitlab.com/gitlab-examples/docker>. + +In the examples below, we are using Docker images tags to specify a +specific version, such as `docker:19.03.1`. If tags like `docker:stable` +are used, you have no control over what version is going to be used and this +can lead to unpredictable behavior, especially when new versions are +released. + +#### TLS enabled + +NOTE: **Note** +This requires GitLab Runner 11.11 or higher. + +The Docker daemon supports connection over TLS and it's done by default +for Docker 19.03.1 or higher. This is the **suggested** way to use the +docker-in-docker service and +[GitLab.com Shared Runners](../../user/gitlab_com/index.html#shared-runners) +support this. 1. Install [GitLab Runner](https://docs.gitlab.com/runner/install). @@ -113,22 +166,21 @@ In order to do that, follow the steps: --registration-token REGISTRATION_TOKEN \ --executor docker \ --description "My Docker Runner" \ - --docker-image "docker:stable" \ - --docker-privileged + --docker-image "docker:19.03.1" \ + --docker-privileged \ + --docker-volumes "/certs/client" ``` The above command will register a new Runner to use the special - `docker:stable` image which is provided by Docker. **Notice that it's using - the `privileged` mode to start the build and service containers.** If you - want to use [docker-in-docker] mode, you always have to use `privileged = true` - in your Docker containers. + `docker:19.03.1` image, which is provided by Docker. **Notice that it's + using the `privileged` mode to start the build and service + containers.** If you want to use [docker-in-docker] mode, you always + have to use `privileged = true` in your Docker containers. - DANGER: **Danger:** - By enabling `--docker-privileged`, you are effectively disabling all of - the security mechanisms of containers and exposing your host to privilege - escalation which can lead to container breakout. For more information, check - out the official Docker documentation on - [Runtime privilege and Linux capabilities][docker-cap]. + This will also mount `/certs/client` for the service and build + container, which is needed for the docker client to use the + certificates inside of that directory. For more information how + Docker with TLS works check <https://hub.docker.com/_/docker/#tls>. The above command will create a `config.toml` entry similar to this: @@ -139,41 +191,48 @@ In order to do that, follow the steps: executor = "docker" [runners.docker] tls_verify = false - image = "docker:stable" + image = "docker:19.03.1" privileged = true disable_cache = false - volumes = ["/cache"] + volumes = ["/certs/client", "/cache"] [runners.cache] - Insecure = false - ``` + [runners.cache.s3] + [runners.cache.gcs] + ``` 1. You can now use `docker` in the build script (note the inclusion of the - `docker:dind` service): + `docker:19.03.1-dind` service): ```yaml - image: docker:stable + image: docker:19.03.1 variables: - # When using dind service we need to instruct docker, to talk with the - # daemon started inside of the service. The daemon is available with - # a network connection instead of the default /var/run/docker.sock socket. + # When using dind service, we need to instruct docker, to talk with + # the daemon started inside of the service. The daemon is available + # with a network connection instead of the default + # /var/run/docker.sock socket. docker:19.03.1 does this automatically + # by setting the DOCKER_HOST in + # https://github.com/docker-library/docker/blob/d45051476babc297257df490d22cbd806f1b11e4/19.03.1/docker-entrypoint.sh#L23-L29 # # The 'docker' hostname is the alias of the service container as described at - # https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services + # https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services. # - # Note that if you're using the Kubernetes executor, the variable should be set to - # tcp://localhost:2375/ because of how the Kubernetes executor connects services - # to the job container - # DOCKER_HOST: tcp://localhost:2375/ + # Note that if you're using the Kubernetes executor, the variable + # should be set to tcp://localhost:2376/ because of how the + # Kubernetes executor connects services to the job container + # DOCKER_HOST: tcp://localhost:2376/ # - # For non-Kubernetes executors, we use tcp://docker:2375/ - DOCKER_HOST: tcp://docker:2375/ # When using dind, it's wise to use the overlayfs driver for # improved performance. DOCKER_DRIVER: overlay2 + # Specify to Docker where to create the certificates, Docker will + # create them automatically on boot, and will create + # `/certs/client` that will be shared between the service and job + # container, thanks to volume mount from config.toml + DOCKER_TLS_CERTDIR: "/certs" services: - - docker:dind + - docker:19.03.1-dind before_script: - docker info @@ -185,33 +244,70 @@ In order to do that, follow the steps: - docker run my-docker-image /script/to/run/tests ``` -Docker-in-Docker works well, and is the recommended configuration, but it is -not without its own challenges: +#### TLS disabled -- When using docker-in-docker, each job is in a clean environment without the past - history. Concurrent jobs work fine because every build gets it's own - instance of Docker engine so they won't conflict with each other. But this - also means jobs can be slower because there's no caching of layers. -- By default, `docker:dind` uses `--storage-driver vfs` which is the slowest - form offered. To use a different driver, see - [Using the overlayfs driver](#using-the-overlayfs-driver). -- Since the `docker:dind` container and the runner container don't share their - root filesystem, the job's working directory can be used as a mount point for - children containers. For example, if you have files you want to share with a - child container, you may create a subdirectory under `/builds/$CI_PROJECT_PATH` - and use it as your mount point (for a more thorough explanation, check [issue - #41227](https://gitlab.com/gitlab-org/gitlab-ce/issues/41227)): +Sometimes there are legitimate reasons why you might want to disable TLS. +For example, you have no control over the GitLab Runner configuration +that you are using. - ```yaml - variables: - MOUNT_POINT: /builds/$CI_PROJECT_PATH/mnt +Assuming that the Runner `config.toml` is similar to: - script: - - mkdir -p "$MOUNT_POINT" - - docker run -v "$MOUNT_POINT:/mnt" my-docker-image - ``` +```toml +[[runners]] + url = "https://gitlab.com/" + token = TOKEN + executor = "docker" + [runners.docker] + tls_verify = false + image = "docker:19.03.1" + privileged = true + disable_cache = false + volumes = ["/cache"] + [runners.cache] + [runners.cache.s3] + [runners.cache.gcs] +``` -An example project using this approach can be found here: <https://gitlab.com/gitlab-examples/docker>. +You can now use `docker` in the build script (note the inclusion of the +`docker:19.03.1-dind` service): + +```yaml +image: docker:19.03.1 + +variables: + # When using dind service we need to instruct docker, to talk with the + # daemon started inside of the service. The daemon is available with + # a network connection instead of the default /var/run/docker.sock socket. + # + # The 'docker' hostname is the alias of the service container as described at + # https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services + # + # Note that if you're using the Kubernetes executor, the variable should be set to + # tcp://localhost:2375/ because of how the Kubernetes executor connects services + # to the job container + # DOCKER_HOST: tcp://localhost:2375/ + # + # For non-Kubernetes executors, we use tcp://docker:2375/ + DOCKER_HOST: tcp://docker:2375/ + # When using dind, it's wise to use the overlayfs driver for + # improved performance. + DOCKER_DRIVER: overlay2 + # + # This will instruct Docker not to start over TLS. + DOCKER_TLS_CERTDIR: "" + +services: + - docker:19.03.1-dind + +before_script: + - docker info + +build: + stage: build + script: + - docker build -t my-docker-image . + - docker run my-docker-image /script/to/run/tests +``` ### Use Docker socket binding diff --git a/doc/ci/examples/end_to_end_testing_webdriverio/img/deployed_dependency_update.png b/doc/ci/examples/end_to_end_testing_webdriverio/img/deployed_dependency_update.png Binary files differindex c45d70d7f7a..9fe1739f37e 100644 --- a/doc/ci/examples/end_to_end_testing_webdriverio/img/deployed_dependency_update.png +++ b/doc/ci/examples/end_to_end_testing_webdriverio/img/deployed_dependency_update.png diff --git a/doc/ci/img/collapsible_log.png b/doc/ci/img/collapsible_log.png Binary files differindex 2785033b349..d2a570e246e 100644 --- a/doc/ci/img/collapsible_log.png +++ b/doc/ci/img/collapsible_log.png diff --git a/doc/ci/img/deployments_view.png b/doc/ci/img/deployments_view.png Binary files differindex 12090434bef..9e2b7e89577 100644 --- a/doc/ci/img/deployments_view.png +++ b/doc/ci/img/deployments_view.png diff --git a/doc/ci/img/environments_available.png b/doc/ci/img/environments_available.png Binary files differindex 48fc6effc2d..6c64e9398f7 100644 --- a/doc/ci/img/environments_available.png +++ b/doc/ci/img/environments_available.png diff --git a/doc/ci/img/environments_mr_review_app.png b/doc/ci/img/environments_mr_review_app.png Binary files differindex 6a7b7ce5679..86c20d8d3b6 100644 --- a/doc/ci/img/environments_mr_review_app.png +++ b/doc/ci/img/environments_mr_review_app.png diff --git a/doc/ci/img/manual_job_variables.png b/doc/ci/img/manual_job_variables.png Binary files differindex c7d62477cdd..a5ed351fdcd 100644 --- a/doc/ci/img/manual_job_variables.png +++ b/doc/ci/img/manual_job_variables.png diff --git a/doc/ci/introduction/img/gitlab_workflow_example_11_9.png b/doc/ci/introduction/img/gitlab_workflow_example_11_9.png Binary files differindex 204e9c462e5..f3fb9444b55 100644 --- a/doc/ci/introduction/img/gitlab_workflow_example_11_9.png +++ b/doc/ci/introduction/img/gitlab_workflow_example_11_9.png diff --git a/doc/ci/introduction/img/gitlab_workflow_example_extended_11_11.png b/doc/ci/introduction/img/gitlab_workflow_example_extended_11_11.png Binary files differindex 5089a1088c5..a0874f66eaa 100644 --- a/doc/ci/introduction/img/gitlab_workflow_example_extended_11_11.png +++ b/doc/ci/introduction/img/gitlab_workflow_example_extended_11_11.png diff --git a/doc/ci/merge_request_pipelines/img/merge_request.png b/doc/ci/merge_request_pipelines/img/merge_request.png Binary files differindex d03fdc6a885..bb64e17cc91 100644 --- a/doc/ci/merge_request_pipelines/img/merge_request.png +++ b/doc/ci/merge_request_pipelines/img/merge_request.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline.png Binary files differindex 58d5581f628..6d4b66824e1 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline.png +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline_config.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline_config.png Binary files differindex 0a84e61d284..3ee9d8ec93b 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline_config.png +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline_config.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_cancel_v12_0.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_cancel_v12_0.png Binary files differindex 1561fdcc7a5..d7720ac1143 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_cancel_v12_0.png +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_cancel_v12_0.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_config_v12_0.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_config_v12_0.png Binary files differindex fb0af43556e..9da959ad440 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_config_v12_0.png +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_config_v12_0.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_failure.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_failure.png Binary files differindex a8916e5721c..8a795fff432 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_failure.png +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_failure.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_immediate_merge.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_immediate_merge.png Binary files differindex 65ff7e3d674..03bc61129ba 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_immediate_merge.png +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_immediate_merge.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_position_v12_0.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_position_v12_0.png Binary files differindex 70916bc0e00..ec4b157d428 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_position_v12_0.png +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_position_v12_0.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_v12_0.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_v12_0.png Binary files differindex f20108157d2..a4d0c8cf0e6 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_v12_0.png +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_v12_0.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_when_pipeline_succeeds_v12_0.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_when_pipeline_succeeds_v12_0.png Binary files differindex 62c2f2f5ff5..45762b8e85e 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_when_pipeline_succeeds_v12_0.png +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_when_pipeline_succeeds_v12_0.png diff --git a/doc/ci/review_apps/img/review_button.png b/doc/ci/review_apps/img/review_button.png Binary files differindex 0b231c50858..4f1cf4d7cfd 100644 --- a/doc/ci/review_apps/img/review_button.png +++ b/doc/ci/review_apps/img/review_button.png diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index c63b1e104ed..01edd873a8d 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -94,7 +94,7 @@ This means that the value of the variable will be hidden in job logs, though it must match certain requirements to do so: - The value must be in a single line. -- The value must only consist of characters from the Base64 alphabet, defined in [RFC4648](https://tools.ietf.org/html/rfc4648). +- The value must only consist of characters from the Base64 alphabet ([RFC4648](https://tools.ietf.org/html/rfc4648)) with the addition of `@` and `:`. - The value must be at least 8 characters long. - The value must not use variables. diff --git a/doc/ci/variables/img/custom_variables_output.png b/doc/ci/variables/img/custom_variables_output.png Binary files differindex 29f5c63b3d9..797e9ec07b9 100644 --- a/doc/ci/variables/img/custom_variables_output.png +++ b/doc/ci/variables/img/custom_variables_output.png diff --git a/doc/ci/variables/img/new_custom_variables_example.png b/doc/ci/variables/img/new_custom_variables_example.png Binary files differindex efe104efe4c..bb60e6bab21 100644 --- a/doc/ci/variables/img/new_custom_variables_example.png +++ b/doc/ci/variables/img/new_custom_variables_example.png diff --git a/doc/ci/variables/img/override_variable_manual_pipeline.png b/doc/ci/variables/img/override_variable_manual_pipeline.png Binary files differindex 3c8c59720cf..c77c5cb7764 100644 --- a/doc/ci/variables/img/override_variable_manual_pipeline.png +++ b/doc/ci/variables/img/override_variable_manual_pipeline.png diff --git a/doc/ci/variables/img/variable_types_usage_example.png b/doc/ci/variables/img/variable_types_usage_example.png Binary files differindex 0e8bde891fe..c2ae32fd048 100644 --- a/doc/ci/variables/img/variable_types_usage_example.png +++ b/doc/ci/variables/img/variable_types_usage_example.png diff --git a/doc/customization/branded_login_page.md b/doc/customization/branded_login_page.md index b892f59d777..afcc2b71284 100644 --- a/doc/customization/branded_login_page.md +++ b/doc/customization/branded_login_page.md @@ -1,19 +1,38 @@ -# Changing the appearance of the login page +--- +type: howto +--- -GitLab offers a way to put your company's identity on the login page of your GitLab server and make it a branded login page. +# Changing the logo and description on the login page -By default, the page shows the GitLab logo and description. +You can customize the login page of your GitLab server to show the logo and +description of your organization. + +By default, the page shows the GitLab logo and description: ![default_login_page](branded_login_page/default_login_page.png) -## Changing the appearance of the login page +To customize the login page: -Navigate to the **Admin** area and go to the **Appearance** page. +1. Navigate to the **Admin** area and go to the **Appearance** page. +1. Fill in your desired Title and Description. You can also choose an image file + of the logo for your organization. -Fill in the required details like Title, Description and upload the company logo. + ![appearance](branded_login_page/appearance.png) -![appearance](branded_login_page/appearance.png) +1. Save your changes. -After saving the page, your GitLab login page will have the details you filled in: +Your GitLab login page will display the details you provided: ![company_login_page](branded_login_page/custom_sign_in.png) + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/customization/branded_page_and_email_header.md b/doc/customization/branded_page_and_email_header.md index 9a0f0b382fa..370c1461d30 100644 --- a/doc/customization/branded_page_and_email_header.md +++ b/doc/customization/branded_page_and_email_header.md @@ -1,15 +1,37 @@ -# Changing the logo on the overall page and email header +--- +type: howto +--- -Navigate to the **Admin** area and go to the **Appearance** page. +# Changing the navigation bar and email header logo -Upload the custom logo (**Header logo**) in the section **Navigation bar**. +You can customize the logo that appears in email headers and in the navigation +bar on pages that are displayed by your GitLab server. -![appearance](branded_page_and_email_header/appearance.png) +1. Navigate to the **Admin** area and go to the **Appearance** page, then locate + the **Navigation bar** section. +1. For the **Header Logo**, choose an image file of the logo for your + organization. -After saving the page, your GitLab navigation bar will contain the custom logo: + ![appearance](branded_page_and_email_header/appearance.png) + +1. Save your changes. + +Your GitLab navigation bar will display the custom logo: ![custom_brand_header](branded_page_and_email_header/custom_brand_header.png) -The GitLab pipeline emails will also have the custom logo: +The GitLab pipeline emails will also display the custom logo: ![custom_email_header](branded_page_and_email_header/custom_email_header.png) + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/customization/favicon.md b/doc/customization/favicon.md index 45a18159b5e..dbde6e8c03b 100644 --- a/doc/customization/favicon.md +++ b/doc/customization/favicon.md @@ -1,16 +1,37 @@ +--- +type: howto +--- + # Changing the favicon > [Introduced][ce-14497] in GitLab 11.0. [ce-14497]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14497 -Navigate to the **Admin** area and go to the **Appearance** page. +You can customize the favicon (the icon displayed in your web browser's +address bar and web page tabs) for your GitLab server. + +1. Navigate to the **Admin** area and go to the **Appearance** page, then + locate the **Favicon** section. +1. Upload an image file of your favicon. -Upload the custom favicon (**Favicon**) in the section **Favicon**. + ![appearance](favicon/appearance.png) -![appearance](favicon/appearance.png) +1. Save your changes. -After saving the page, the new favicon will be shown in the browser. The main -favicon as well as the CI status icons will show the custom icon: +Your new favicon will display in the browser. The main favicon and the CI +status icons will show the custom icon: ![custom_favicon](favicon/custom_favicon.png) + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/customization/help_message.md b/doc/customization/help_message.md index c2e592d03bf..a4d8f295750 100644 --- a/doc/customization/help_message.md +++ b/doc/customization/help_message.md @@ -1,13 +1,36 @@ -# GitLab Help custom text +--- +type: howto +--- -In larger organizations it is useful to have information about who has the responsibility of maintaining the company GitLab server. +# Customizing the 'Help' and login page messages -1. Navigate to the admin area, click on **Preferences** and expand **Help page**. +In large organizations, it is useful to have information about who maintains +the company GitLab server. You can customize and display this information on +the GitLab login page and on the GitLab server's `/help` page. -1. Under **Help text** fill in the required information about the person(s) administering GitLab or any other information relevant to your needs. +1. Navigate to the **Admin** area, then click on **Preferences** and expand + **Help page**. +1. Under **Help page text**, fill in the required information about the + person(s) administering GitLab. This text can also contain any other + information that you wish to display to users. - ![help message](help_message/help_text.png) + ![help message](help_message/help_text.png) -1. After saving the page this information will be shown on the GitLab login page and on the GitLab `/help` page (e.g., <https://gitlab.com/help>). +1. Save your changes. - ![help text on help page](help_message/help_text_on_help_page.png) +The information you entered will be shown on the GitLab login page and on the +GitLab `/help` page (e.g., <https://gitlab.com/help>). + +![help text on help page](help_message/help_text_on_help_page.png) + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/customization/help_message/help_text.png b/doc/customization/help_message/help_text.png Binary files differindex 99697a106bf..5fcabcdb757 100644 --- a/doc/customization/help_message/help_text.png +++ b/doc/customization/help_message/help_text.png diff --git a/doc/customization/index.md b/doc/customization/index.md index 0198059297f..f17a2d80e2c 100644 --- a/doc/customization/index.md +++ b/doc/customization/index.md @@ -1,18 +1,18 @@ --- +type: index description: Learn how to customize GitLab's appearance for self-managed installations. --- # Customizing GitLab's appearance **(CORE ONLY)** -For GitLab self-managed instances, it's possible to customize -a few pages. +For GitLab self-managed instances, you can customize the page logo, +email headers, favicon, and several other aspects of GitLab's appearance. -Read through the following documents to adjust GitLab's -look and feel to meet your needs: +The following pages explain how to customize the appearance of your instance: -- [Custom login page](branded_login_page.md) -- [Custom header and email logo](branded_page_and_email_header.md) -- [Custom favicon](favicon.md) -- [Libravatar](libravatar.md) -- [New project page](new_project_page.md) -- [Custom `/help` message](help_message.md)
\ No newline at end of file +- [Changing the logo and description on the login page](branded_login_page.md) +- [Changing the navigation bar and email header logo](branded_page_and_email_header.md) +- [Changing the favicon](favicon.md) +- [Customizing the new project page](new_project_page.md) +- [Customizing the `/help` and login page messages](help_message.md) +- [Using the Libravatar service with GitLab](libravatar.md) diff --git a/doc/customization/libravatar.md b/doc/customization/libravatar.md index e618f3be2fe..1c3bf877fa1 100644 --- a/doc/customization/libravatar.md +++ b/doc/customization/libravatar.md @@ -1,14 +1,20 @@ -# Use Libravatar service with GitLab +--- +type: howto +--- -GitLab by default supports [Gravatar](https://gravatar.com) avatar service. -Libravatar is a service which delivers your avatar (profile picture) to other websites and their API is -[heavily based on gravatar](https://wiki.libravatar.org/api/). +# Using the Libravatar service with GitLab -This means that it is not complicated to switch to Libravatar avatar service or even self hosted Libravatar server. +GitLab by default supports the [Gravatar](https://gravatar.com) avatar service. + +Libravatar is another service that delivers your avatar (profile picture) to +other websites. The Libravatar API is +[heavily based on gravatar](https://wiki.libravatar.org/api/), so you can +easily switch to the Libravatar avatar service or even a self-hosted Libravatar +server. ## Configuration -In [gitlab.yml gravatar section](https://gitlab.com/gitlab-org/gitlab-ce/blob/672bd3902d86b78d730cea809fce312ec49d39d7/config/gitlab.yml.example#L122) set +In the [gitlab.yml gravatar section](https://gitlab.com/gitlab-org/gitlab-ce/blob/672bd3902d86b78d730cea809fce312ec49d39d7/config/gitlab.yml.example#L122), set the configuration options as follows: ### For HTTP @@ -29,12 +35,14 @@ the configuration options as follows: ssl_url: "https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon" ``` -### Self-hosted +### Self-hosted Libravatar server -If you are [running your own libravatar service](https://wiki.libravatar.org/running_your_own/) the URL will be different in the configuration -but the important part is to provide the same placeholders so GitLab can parse the URL correctly. +If you are [running your own libravatar service](https://wiki.libravatar.org/running_your_own/), +the URL will be different in the configuration, but you must provide the same +placeholders so GitLab can parse the URL correctly. -For example, you host a service on `http://libravatar.example.com` the `plain_url` you need to supply in `gitlab.yml` is +For example, you host a service on `http://libravatar.example.com` and the +`plain_url` you need to supply in `gitlab.yml` is `http://libravatar.example.com/avatar/%{hash}?s=%{size}&d=identicon` @@ -42,37 +50,52 @@ For example, you host a service on `http://libravatar.example.com` the `plain_ur In `/etc/gitlab/gitlab.rb`: -#### For http +#### For HTTP ```ruby gitlab_rails['gravatar_enabled'] = true gitlab_rails['gravatar_plain_url'] = "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon" ``` -#### For https +#### For HTTPS ```ruby gitlab_rails['gravatar_enabled'] = true gitlab_rails['gravatar_ssl_url'] = "https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon" ``` -Run `sudo gitlab-ctl reconfigure` for changes to take effect. +Then run `sudo gitlab-ctl reconfigure` for the changes to take effect. ## Default URL for missing images -[Libravatar supports different sets](https://wiki.libravatar.org/api/) of `missing images` for emails not found on the Libravatar service. - -In order to use a different set other than `identicon`, replace `&d=identicon` portion of the URL with another supported set. -For example, you can use `retro` set in which case the URL would look like: `plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=retro"` +[Libravatar supports different sets](https://wiki.libravatar.org/api/) of +missing images for user email addresses that are not found on the Libravatar +service. -## Usage examples +In order to use a set other than `identicon`, replace the `&d=identicon` +portion of the URL with another supported set. +For example, you can use the `retro` set, in which case the URL would look like: +`plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=retro"` -### For Microsoft Office 365 +## Usage examples for Microsoft Office 365 -If your users are Office 365-users, the "GetPersonaPhoto" service can be used. Note that this service requires login, so this use case is -most useful in a corporate installation, where all users have access to Office 365. +If your users are Office 365 users, the `GetPersonaPhoto` service can be used. +Note that this service requires a login, so this use case is most useful in a +corporate installation where all users have access to Office 365. ```ruby gitlab_rails['gravatar_plain_url'] = 'http://outlook.office365.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120' gitlab_rails['gravatar_ssl_url'] = 'https://outlook.office365.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120' ``` + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/customization/new_project_page.md b/doc/customization/new_project_page.md index 148bf9512c6..43b95a76d08 100644 --- a/doc/customization/new_project_page.md +++ b/doc/customization/new_project_page.md @@ -1,20 +1,38 @@ +--- +type: howto +--- + # Customizing the new project page -It is possible to add a markdown-formatted message to your GitLab -new project page. +You can add a markdown-formatted message to your GitLab new project page. By default, the new project page shows a sidebar with general information: -![](new_project_page/default_new_project_page.png) +![default_new_project_page](new_project_page/default_new_project_page.png) + +To customize the information in the sidebar: + +1. Navigate to the **Admin** area and go to the **Appearance** page, then + locate the **New project pages** section. +1. Fill in your new project project guidelines: + + ![appearance_settings](new_project_page/appearance_settings.png) -## Changing the appearance of the new project page +1. Save the page. -Navigate to the **Admin** area and go to the **Appearance** page. +Your new project page will show the customized guidelines in the sidebar, below +the general information: -Fill in your project guidelines: +![custom_new_project_page](new_project_page/custom_new_project_page.png) -![](new_project_page/appearance_settings.png) +<!-- ## Troubleshooting -After saving the page, your new project page will show the guidelines in the sidebar, below the general information: +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. -![](new_project_page/custom_new_project_page.png) +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/customization/system_header_and_footer_messages/appearance.png b/doc/customization/system_header_and_footer_messages/appearance.png Binary files differindex fd315bb6c07..d5a66bcb9f1 100644 --- a/doc/customization/system_header_and_footer_messages/appearance.png +++ b/doc/customization/system_header_and_footer_messages/appearance.png diff --git a/doc/development/fe_guide/architecture.md b/doc/development/fe_guide/architecture.md index 49b74b5ebcf..3d27f67a8a6 100644 --- a/doc/development/fe_guide/architecture.md +++ b/doc/development/fe_guide/architecture.md @@ -11,7 +11,7 @@ Architectural decisions should be accessible to everyone, so please document them in the relevant Merge Request discussion or by updating our documentation when appropriate. -You can find the Frontend Architecture experts on the [team page](https://about.gitlab.com/company/team). +You can find the Frontend Architecture experts on the [team page](https://about.gitlab.com/company/team/). ## Examples diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index 55b719227e5..4fc5dfc8c3d 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -47,7 +47,7 @@ new Vue({ }); ``` -Read more about [Vue Apollo][vue-apollo] in the [Vue Apollo documentation][vue-apollo-docs]. +Read more about [Vue Apollo][vue-apollo] in the [Vue Apollo documentation](https://vue-apollo.netlify.com/guide/). ### Local state with Apollo @@ -118,7 +118,6 @@ Read more about the [Apollo] client in the [Apollo documentation](https://www.ap [Apollo]: https://www.apollographql.com/ [vue-apollo]: https://github.com/Akryum/vue-apollo/ -[vue-apollo-docs]: https://akryum.github.io/vue-apollo/ [feature-flags]: ../feature_flags.md [default-client]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/lib/graphql.js [vue-test-utils]: https://vue-test-utils.vuejs.org/ diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md index b0bbb4cc4b2..d3fa350b847 100644 --- a/doc/development/fe_guide/style_guide_js.md +++ b/doc/development/fe_guide/style_guide_js.md @@ -49,8 +49,8 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/ ``` 1. There are few rules that we need to disable due to technical debt. Which are: - 1. [no-new][eslint-new] - 1. [class-methods-use-this][eslint-this] + 1. [no-new](https://eslint.org/docs/rules/no-new) + 1. [class-methods-use-this](https://eslint.org/docs/rules/class-methods-use-this) 1. When they are needed _always_ place ESlint directive comment blocks on the first line of a script, followed by any global declarations, then a blank newline prior to any imports or code. @@ -714,8 +714,6 @@ The goal of this accord is to make sure we are all on the same page. [airbnb-js-style-guide]: https://github.com/airbnb/javascript [eslintrc]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.eslintrc -[eslint-this]: http://eslint.org/docs/rules/class-methods-use-this -[eslint-new]: http://eslint.org/docs/rules/no-new [eslint-plugin-vue]: https://github.com/vuejs/eslint-plugin-vue [eslint-plugin-vue-rules]: https://github.com/vuejs/eslint-plugin-vue#bulb-rules [vue-order]: https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/order-in-components.md diff --git a/doc/development/img/architecture_simplified.png b/doc/development/img/architecture_simplified.png Binary files differindex 1698c167c5e..1ad57b65468 100644 --- a/doc/development/img/architecture_simplified.png +++ b/doc/development/img/architecture_simplified.png diff --git a/doc/development/img/distributed_tracing_jaeger_ui.png b/doc/development/img/distributed_tracing_jaeger_ui.png Binary files differindex 57517dacced..dcd18b1ec9f 100644 --- a/doc/development/img/distributed_tracing_jaeger_ui.png +++ b/doc/development/img/distributed_tracing_jaeger_ui.png diff --git a/doc/development/img/distributed_tracing_performance_bar.png b/doc/development/img/distributed_tracing_performance_bar.png Binary files differindex c9998cedd2d..8c819045104 100644 --- a/doc/development/img/distributed_tracing_performance_bar.png +++ b/doc/development/img/distributed_tracing_performance_bar.png diff --git a/doc/development/new_fe_guide/development/performance.md b/doc/development/new_fe_guide/development/performance.md index c54b8305991..d41239693bf 100644 --- a/doc/development/new_fe_guide/development/performance.md +++ b/doc/development/new_fe_guide/development/performance.md @@ -5,7 +5,7 @@ We have a performance dashboard available in one of our [grafana instances](https://dashboards.gitlab.net/d/1EBTz3Dmz/sitespeed-page-summary?orgId=1). This dashboard automatically aggregates metric data from [sitespeed.io](https://www.sitespeed.io/) every 6 hours. These changes are displayed after a set number of pages are aggregated. These pages can be found inside a text file in the gitlab-build-images [repository](https://gitlab.com/gitlab-org/gitlab-build-images) called [gitlab.txt](https://gitlab.com/gitlab-org/gitlab-build-images/blob/master/scripts/gitlab.txt) -Any frontend engineer can contribute to this dashboard. They can contribute by adding or removing urls of pages from this text file. Please have a [frontend monitoring expert](https://about.gitlab.com/company/team) review your changes before assigning to a maintainer of the `gitlab-build-images` project. The changes will go live on the next scheduled run after the changes are merged into `master`. +Any frontend engineer can contribute to this dashboard. They can contribute by adding or removing urls of pages from this text file. Please have a [frontend monitoring expert](https://about.gitlab.com/company/team/) review your changes before assigning to a maintainer of the `gitlab-build-images` project. The changes will go live on the next scheduled run after the changes are merged into `master`. There are 3 recommended high impact metrics to review on each page: diff --git a/doc/development/new_fe_guide/development/testing.md b/doc/development/new_fe_guide/development/testing.md index 2b62c2a41fe..f7ea496d935 100644 --- a/doc/development/new_fe_guide/development/testing.md +++ b/doc/development/new_fe_guide/development/testing.md @@ -261,7 +261,7 @@ scenario 'successfully', :js do end ``` -The steps of each test are written using capybara methods ([documentation](https://www.rubydoc.info/gems/capybara/2.15.1)). +The steps of each test are written using capybara methods ([documentation](https://www.rubydoc.info/gems/capybara)). Bear in mind <abbr title="XMLHttpRequest">XHR</abbr> calls might require you to use `wait_for_requests` in between steps, like so: diff --git a/doc/development/ux_guide/animation.md b/doc/development/ux_guide/animation.md index 583ff19bc69..a998ab74a96 100644 --- a/doc/development/ux_guide/animation.md +++ b/doc/development/ux_guide/animation.md @@ -1,5 +1,5 @@ --- -redirect_to: 'https://design.gitlab.com/foundations/motion' +redirect_to: 'https://design.gitlab.com/product-foundations/motion' --- -The content of this document was moved into the [GitLab Design System](https://design.gitlab.com). +The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/product-foundations/motion). diff --git a/doc/development/ux_guide/illustrations.md b/doc/development/ux_guide/illustrations.md index ed072b6515f..3592d25c95d 100644 --- a/doc/development/ux_guide/illustrations.md +++ b/doc/development/ux_guide/illustrations.md @@ -1,5 +1,5 @@ --- -redirect_to: 'https://design.gitlab.com/foundations/illustration/' +redirect_to: 'https://design.gitlab.com/product-foundations/illustration' --- -The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/). +The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/product-foundations/illustration). diff --git a/doc/install/docker.md b/doc/install/docker.md index 06da65189ba..e0cef71a4d8 100644 --- a/doc/install/docker.md +++ b/doc/install/docker.md @@ -10,7 +10,7 @@ GitLab provides official Docker images allowing you to easily take advantage of ## Omnibus GitLab based images -GitLab maintains a set of [official Docker images](https://hub.docker.com/r/gitlab) based on our [Omnibus GitLab package](https://docs.gitlab.com/omnibus/README.html). These images include: +GitLab maintains a set of [official Docker images](https://hub.docker.com/u/gitlab) based on our [Omnibus GitLab package](https://docs.gitlab.com/omnibus/README.html). These images include: - [GitLab Community Edition](https://hub.docker.com/r/gitlab/gitlab-ce/) - [GitLab Enterprise Edition](https://hub.docker.com/r/gitlab/gitlab-ee/) diff --git a/doc/integration/img/limit_namespace_filter.png b/doc/integration/img/limit_namespace_filter.png Binary files differindex 88f5caa41db..437aecad467 100644 --- a/doc/integration/img/limit_namespace_filter.png +++ b/doc/integration/img/limit_namespace_filter.png diff --git a/doc/integration/img/limit_namespaces_projects_options.png b/doc/integration/img/limit_namespaces_projects_options.png Binary files differindex 488341f7e92..fa666c7491e 100644 --- a/doc/integration/img/limit_namespaces_projects_options.png +++ b/doc/integration/img/limit_namespaces_projects_options.png diff --git a/doc/integration/img/salesforce_app_details.png b/doc/integration/img/salesforce_app_details.png Binary files differindex 00e66f07282..c7a4084102e 100644 --- a/doc/integration/img/salesforce_app_details.png +++ b/doc/integration/img/salesforce_app_details.png diff --git a/doc/integration/img/salesforce_app_secret_details.png b/doc/integration/img/salesforce_app_secret_details.png Binary files differindex fad2a4a1f97..8734a7a5cbb 100644 --- a/doc/integration/img/salesforce_app_secret_details.png +++ b/doc/integration/img/salesforce_app_secret_details.png diff --git a/doc/integration/img/salesforce_oauth_app_details.png b/doc/integration/img/salesforce_oauth_app_details.png Binary files differindex a5fb680cca6..e29c55df656 100644 --- a/doc/integration/img/salesforce_oauth_app_details.png +++ b/doc/integration/img/salesforce_oauth_app_details.png diff --git a/doc/security/img/outbound_requests_section_v12_2.png b/doc/security/img/outbound_requests_section_v12_2.png Binary files differindex 4fd3c7d9fce..3dc99868a35 100644 --- a/doc/security/img/outbound_requests_section_v12_2.png +++ b/doc/security/img/outbound_requests_section_v12_2.png diff --git a/doc/security/rack_attack.md b/doc/security/rack_attack.md index c772f783f71..b99bfb16829 100644 --- a/doc/security/rack_attack.md +++ b/doc/security/rack_attack.md @@ -20,9 +20,9 @@ For more information on how to use these options see the [Rack Attack README](ht NOTE: **Note:** See [User and IP rate limits](../user/admin_area/settings/user_and_ip_rate_limits.md) -for simpler throttles that are configured in UI. +for simpler limits that are configured in the UI. -NOTE: **Note:** Starting with 11.2, Rack Attack is disabled by default. If your +NOTE: **Note:** Starting with GitLab 11.2, Rack Attack is disabled by default. If your instance is not exposed to the public internet, it is recommended that you leave Rack Attack disabled. @@ -31,13 +31,13 @@ Rack Attack disabled. If set up as described in the [Settings](#settings) section below, two behaviors will be enabled: -- Protected paths will be throttled -- Failed authentications for Git and container registry requests will trigger a temporary IP ban +- Protected paths will be throttled. +- Failed authentications for Git and container registry requests will trigger a temporary IP ban. ### Protected paths throttle -GitLab responds with HTTP status code 429 to POST requests at protected paths -over 10 requests per minute per IP address. +GitLab responds with HTTP status code `429` to POST requests at protected paths +that exceed 10 requests per minute per IP address. By default, protected paths are: @@ -62,16 +62,16 @@ Retry-After: 60 For example, the following are limited to a maximum 10 requests per minute: -- user sign-in -- user sign-up (if enabled) -- user password reset +- User sign-in +- User sign-up (if enabled) +- User password reset -After trying for 10 times, the client will -have to wait a minute before to be able to try again. +After 10 requests, the client must wait a minute before it can +try again. ### Git and container registry failed authentication ban -GitLab responds with HTTP status code 403 for 1 hour, if 30 failed +GitLab responds with HTTP status code `403` for 1 hour, if 30 failed authentication requests were received in a 3-minute period from a single IP address. This applies only to Git requests and container registry (`/jwt/auth`) requests @@ -145,7 +145,7 @@ If you want more restrictive/relaxed throttle rules, edit For example, more relaxed throttle rules will be if you set `limit: 3` and `period: 1.seconds` (this will allow 3 requests per second). You can also add other paths to the protected list by adding to `paths_to_be_protected` -variable. If you change any of these settings do not forget to restart your +variable. If you change any of these settings you must restart your GitLab instance. ## Remove blocked IPs from Rack Attack via Redis diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md index 8b4a2f1630b..ad196e27f53 100644 --- a/doc/topics/authentication/index.md +++ b/doc/topics/authentication/index.md @@ -23,7 +23,7 @@ This page gathers all the resources for the topic **Authentication** within GitL - [How to Configure LDAP with GitLab CE](../../administration/auth/how_to_configure_ldap_gitlab_ce/index.md) - [How to Configure LDAP with GitLab EE](../../administration/auth/how_to_configure_ldap_gitlab_ee/index.md) **(STARTER)** - [Feature Highlight: LDAP Integration](https://about.gitlab.com/2014/07/10/feature-highlight-ldap-sync/) - - [Debugging LDAP](https://about.gitlab.com/handbook/support/workflows/support-engineering/ldap/debugging_ldap.html) + - [Debugging LDAP](https://about.gitlab.com/handbook/support/workflows/debugging_ldap.html) - **Integrations:** - [OmniAuth](../../integration/omniauth.md) - [Authentiq OmniAuth Provider](../../administration/auth/authentiq.md#authentiq-omniauth-provider) diff --git a/doc/topics/git/useful_git_commands.md b/doc/topics/git/useful_git_commands.md index 84406805350..030e62f485a 100644 --- a/doc/topics/git/useful_git_commands.md +++ b/doc/topics/git/useful_git_commands.md @@ -149,7 +149,7 @@ gitk --follow <file> ### Use a custom SSH key for a git command -```text +```sh GIT_SSH_COMMAND="ssh -i ~/.ssh/gitlabadmin" git <command> ``` @@ -157,13 +157,13 @@ GIT_SSH_COMMAND="ssh -i ~/.ssh/gitlabadmin" git <command> With SSH: -```text +```sh GIT_SSH_COMMAND="ssh -vvv" git clone <git@url> ``` With HTTPS: -```text +```sh GIT_TRACE_PACKET=1 GIT_TRACE=2 GIT_CURL_VERBOSE=1 git clone <url> ``` diff --git a/doc/user/admin_area/img/abuse_report_blocked_user.png b/doc/user/admin_area/img/abuse_report_blocked_user.png Binary files differindex 0cb4c7bb8ac..435d8dfe821 100644 --- a/doc/user/admin_area/img/abuse_report_blocked_user.png +++ b/doc/user/admin_area/img/abuse_report_blocked_user.png diff --git a/doc/user/admin_area/img/abuse_reports_page.png b/doc/user/admin_area/img/abuse_reports_page.png Binary files differindex 81dbe976cda..30e932211cb 100644 --- a/doc/user/admin_area/img/abuse_reports_page.png +++ b/doc/user/admin_area/img/abuse_reports_page.png diff --git a/doc/user/admin_area/img/broadcast_messages.png b/doc/user/admin_area/img/broadcast_messages.png Binary files differindex 926d38ae049..f0ae92f8c17 100644 --- a/doc/user/admin_area/img/broadcast_messages.png +++ b/doc/user/admin_area/img/broadcast_messages.png diff --git a/doc/user/admin_area/img/license_details.png b/doc/user/admin_area/img/license_details.png Binary files differindex 2085bb437ad..3e980d9316d 100644 --- a/doc/user/admin_area/img/license_details.png +++ b/doc/user/admin_area/img/license_details.png diff --git a/doc/user/admin_area/settings/email.md b/doc/user/admin_area/settings/email.md index 1f07a4dfdc6..77c9d097283 100644 --- a/doc/user/admin_area/settings/email.md +++ b/doc/user/admin_area/settings/email.md @@ -17,11 +17,10 @@ The logo in the header of some emails can be customized, see the [logo customiza The additional text will appear at the bottom of any email and can be used for legal/auditing/compliance reasons. -1. Go to **Admin area > Settings** (`/admin/application_settings`). -1. Under the **Email** section, change the **Additional text** field. -1. Hit **Save** for the changes to take effect. - -![Admin email settings](img/email_settings.png) +1. Go to **Admin Area > Settings > Preferences** (`/admin/application_settings/preferences`). +1. Expand the **Email** section. +1. Enter your text in the **Additional text** field. +1. Click **Save**. [ee-5031]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/5031 [eep]: https://about.gitlab.com/pricing/ @@ -53,4 +52,4 @@ questions that you know someone might ask. Each scenario can be a third-level heading, e.g. `### Getting error message X`. If you have none to add when creating a doc, leave this section in place -but commented out to help encourage others to add to it in the future. -->
\ No newline at end of file +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/admin_area/settings/img/additional_minutes.png b/doc/user/admin_area/settings/img/additional_minutes.png Binary files differindex d148ed79b92..b159b98c9ce 100644 --- a/doc/user/admin_area/settings/img/additional_minutes.png +++ b/doc/user/admin_area/settings/img/additional_minutes.png diff --git a/doc/user/admin_area/settings/img/admin_required_pipeline.png b/doc/user/admin_area/settings/img/admin_required_pipeline.png Binary files differindex 58488674d51..501b1e3ba0a 100644 --- a/doc/user/admin_area/settings/img/admin_required_pipeline.png +++ b/doc/user/admin_area/settings/img/admin_required_pipeline.png diff --git a/doc/user/admin_area/settings/img/buy_btn.png b/doc/user/admin_area/settings/img/buy_btn.png Binary files differindex 0cc88b8a48f..4fd05c0fba7 100644 --- a/doc/user/admin_area/settings/img/buy_btn.png +++ b/doc/user/admin_area/settings/img/buy_btn.png diff --git a/doc/user/admin_area/settings/img/buy_minutes_card.png b/doc/user/admin_area/settings/img/buy_minutes_card.png Binary files differindex cf4ad34ead7..cab098300cd 100644 --- a/doc/user/admin_area/settings/img/buy_minutes_card.png +++ b/doc/user/admin_area/settings/img/buy_minutes_card.png diff --git a/doc/user/admin_area/settings/img/email_confirmation.png b/doc/user/admin_area/settings/img/email_confirmation.png Binary files differindex 4d888da3416..987aa10c3ce 100644 --- a/doc/user/admin_area/settings/img/email_confirmation.png +++ b/doc/user/admin_area/settings/img/email_confirmation.png diff --git a/doc/user/admin_area/settings/img/email_settings.png b/doc/user/admin_area/settings/img/email_settings.png Binary files differdeleted file mode 100644 index ed0a80d10ce..00000000000 --- a/doc/user/admin_area/settings/img/email_settings.png +++ /dev/null diff --git a/doc/user/admin_area/settings/img/user_and_ip_rate_limits.png b/doc/user/admin_area/settings/img/user_and_ip_rate_limits.png Binary files differindex 2bd85a2fd96..53dc0e4ac87 100644 --- a/doc/user/admin_area/settings/img/user_and_ip_rate_limits.png +++ b/doc/user/admin_area/settings/img/user_and_ip_rate_limits.png diff --git a/doc/user/application_security/img/create_issue_with_list_hover.png b/doc/user/application_security/img/create_issue_with_list_hover.png Binary files differindex 7d70e8299f5..4c38862e68f 100644 --- a/doc/user/application_security/img/create_issue_with_list_hover.png +++ b/doc/user/application_security/img/create_issue_with_list_hover.png diff --git a/doc/user/application_security/img/dismissed_info.png b/doc/user/application_security/img/dismissed_info.png Binary files differindex 64d5cf26ed2..b4470b664d2 100644 --- a/doc/user/application_security/img/dismissed_info.png +++ b/doc/user/application_security/img/dismissed_info.png diff --git a/doc/user/application_security/img/interactive_reports.png b/doc/user/application_security/img/interactive_reports.png Binary files differindex 373b39104db..1b2ef0d3da9 100644 --- a/doc/user/application_security/img/interactive_reports.png +++ b/doc/user/application_security/img/interactive_reports.png diff --git a/doc/user/application_security/img/vulnerability_solution.png b/doc/user/application_security/img/vulnerability_solution.png Binary files differindex 7443b9b6eea..d86b89a5f99 100644 --- a/doc/user/application_security/img/vulnerability_solution.png +++ b/doc/user/application_security/img/vulnerability_solution.png diff --git a/doc/user/application_security/license_management/img/license_management_add_license.png b/doc/user/application_security/license_management/img/license_management_add_license.png Binary files differindex 1e1a698515b..c9a5dc14c57 100644 --- a/doc/user/application_security/license_management/img/license_management_add_license.png +++ b/doc/user/application_security/license_management/img/license_management_add_license.png diff --git a/doc/user/application_security/license_management/img/license_management_decision.png b/doc/user/application_security/license_management/img/license_management_decision.png Binary files differindex 0763130c375..fbf90bec7fd 100644 --- a/doc/user/application_security/license_management/img/license_management_decision.png +++ b/doc/user/application_security/license_management/img/license_management_decision.png diff --git a/doc/user/application_security/license_management/img/license_management_search.png b/doc/user/application_security/license_management/img/license_management_search.png Binary files differindex 7b6006cef9d..b3ffd8d95a1 100644 --- a/doc/user/application_security/license_management/img/license_management_search.png +++ b/doc/user/application_security/license_management/img/license_management_search.png diff --git a/doc/user/application_security/license_management/img/license_management_settings.png b/doc/user/application_security/license_management/img/license_management_settings.png Binary files differindex 1a2bfa78a03..2e3e8888e93 100644 --- a/doc/user/application_security/license_management/img/license_management_settings.png +++ b/doc/user/application_security/license_management/img/license_management_settings.png diff --git a/doc/user/application_security/security_dashboard/img/group_security_dashboard.png b/doc/user/application_security/security_dashboard/img/group_security_dashboard.png Binary files differindex 40689861e2a..85ab124f74c 100644 --- a/doc/user/application_security/security_dashboard/img/group_security_dashboard.png +++ b/doc/user/application_security/security_dashboard/img/group_security_dashboard.png diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard.png Binary files differindex 89b310895d3..baa136fd885 100644 --- a/doc/user/application_security/security_dashboard/img/project_security_dashboard.png +++ b/doc/user/application_security/security_dashboard/img/project_security_dashboard.png diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md index c0106b2cb9e..096730f800c 100644 --- a/doc/user/clusters/applications.md +++ b/doc/user/clusters/applications.md @@ -1,11 +1,13 @@ # GitLab Managed Apps GitLab provides **GitLab Managed Apps**, a one-click install for various applications which can -be added directly to your configured cluster. These applications are -needed for [Review Apps](../../ci/review_apps/index.md) and -[deployments](../../ci/environments.md) when using [Auto DevOps](../../topics/autodevops/index.md). +be added directly to your configured cluster. + +These applications are needed for [Review Apps](../../ci/review_apps/index.md) +and [deployments](../../ci/environments.md) when using [Auto DevOps](../../topics/autodevops/index.md). + You can install them after you -[create a cluster](../project/clusters/index.md#add-new-gke-cluster). +[create a cluster](../project/clusters/index.md#adding-and-removing-clusters). ## Installing applications @@ -20,8 +22,10 @@ This namespace: To see a list of available applications to install: 1. For a: - - Project-level cluster, navigate to your project's **Operations > Kubernetes**. - - Group-level cluster, 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. @@ -160,9 +164,9 @@ file. 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: -- Name -- Email -- Newly created access token +- Name. +- Email. +- Newly created access token. JupyterLab's Git extension enables full version control of your notebooks as well as issuance of Git commands within Jupyter. Git commands can be issued via the **Git** tab on the left panel or via Jupyter's command line prompt. @@ -233,8 +237,10 @@ The applications below can be upgraded. To upgrade an application: 1. For a: - - Project-level cluster, navigate to your project's **Operations > Kubernetes**. - - Group-level cluster, 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. 1. Select your cluster. 1. If an upgrade is available, the **Upgrade** button is displayed. Click the button to upgrade. @@ -263,8 +269,10 @@ The applications below can be uninstalled. To uninstall an application: 1. For a: - - Project-level cluster, navigate to your project's **Operations > Kubernetes**. - - Group-level cluster, 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. 1. Select your cluster. 1. Click the **Uninstall** button for the application. diff --git a/doc/user/clusters/img/jupyter-gitclone.png b/doc/user/clusters/img/jupyter-gitclone.png Binary files differindex 41d467f806a..aff194dea43 100644 --- a/doc/user/clusters/img/jupyter-gitclone.png +++ b/doc/user/clusters/img/jupyter-gitclone.png diff --git a/doc/user/discussions/img/automatically_resolve_outdated_discussions.png b/doc/user/discussions/img/automatically_resolve_outdated_discussions.png Binary files differindex d31216a7e2e..a6fc4b0aef1 100644 --- a/doc/user/discussions/img/automatically_resolve_outdated_discussions.png +++ b/doc/user/discussions/img/automatically_resolve_outdated_discussions.png diff --git a/doc/user/discussions/img/btn_new_issue_for_all_threads.png b/doc/user/discussions/img/btn_new_issue_for_all_threads.png Binary files differindex f24c84a2348..5d86e0ca016 100644 --- a/doc/user/discussions/img/btn_new_issue_for_all_threads.png +++ b/doc/user/discussions/img/btn_new_issue_for_all_threads.png diff --git a/doc/user/discussions/img/commit_comment_mr_context.png b/doc/user/discussions/img/commit_comment_mr_context.png Binary files differindex 7b87d6e44d7..68f58a57757 100644 --- a/doc/user/discussions/img/commit_comment_mr_context.png +++ b/doc/user/discussions/img/commit_comment_mr_context.png diff --git a/doc/user/discussions/img/commit_comment_mr_discussions_tab.png b/doc/user/discussions/img/commit_comment_mr_discussions_tab.png Binary files differindex 4798ff4b658..d88f08eae26 100644 --- a/doc/user/discussions/img/commit_comment_mr_discussions_tab.png +++ b/doc/user/discussions/img/commit_comment_mr_discussions_tab.png diff --git a/doc/user/discussions/img/discussion_comment.png b/doc/user/discussions/img/discussion_comment.png Binary files differindex 685c30e5004..3fec5962363 100644 --- a/doc/user/discussions/img/discussion_comment.png +++ b/doc/user/discussions/img/discussion_comment.png diff --git a/doc/user/discussions/img/image_resolved_discussion.png b/doc/user/discussions/img/image_resolved_discussion.png Binary files differindex 9feded27c92..f6e5a3b66ae 100644 --- a/doc/user/discussions/img/image_resolved_discussion.png +++ b/doc/user/discussions/img/image_resolved_discussion.png diff --git a/doc/user/discussions/img/merge_request_commits_tab.png b/doc/user/discussions/img/merge_request_commits_tab.png Binary files differindex 065d4be61f0..267f3a720dc 100644 --- a/doc/user/discussions/img/merge_request_commits_tab.png +++ b/doc/user/discussions/img/merge_request_commits_tab.png diff --git a/doc/user/discussions/img/mr_review_resolve.png b/doc/user/discussions/img/mr_review_resolve.png Binary files differindex fc6299961a5..ced33682459 100644 --- a/doc/user/discussions/img/mr_review_resolve.png +++ b/doc/user/discussions/img/mr_review_resolve.png diff --git a/doc/user/discussions/img/mr_review_resolve2.png b/doc/user/discussions/img/mr_review_resolve2.png Binary files differindex 1794b682911..2f0be3b6d06 100644 --- a/doc/user/discussions/img/mr_review_resolve2.png +++ b/doc/user/discussions/img/mr_review_resolve2.png diff --git a/doc/user/discussions/img/mr_review_second_comment.png b/doc/user/discussions/img/mr_review_second_comment.png Binary files differindex 204cc840d9e..f345c52e941 100644 --- a/doc/user/discussions/img/mr_review_second_comment.png +++ b/doc/user/discussions/img/mr_review_second_comment.png diff --git a/doc/user/discussions/img/mr_review_second_comment_added.png b/doc/user/discussions/img/mr_review_second_comment_added.png Binary files differindex aa15ca7fb98..61b45431c9e 100644 --- a/doc/user/discussions/img/mr_review_second_comment_added.png +++ b/doc/user/discussions/img/mr_review_second_comment_added.png diff --git a/doc/user/discussions/img/mr_review_start.png b/doc/user/discussions/img/mr_review_start.png Binary files differindex 0f52bee7d89..08b4c6bb82b 100644 --- a/doc/user/discussions/img/mr_review_start.png +++ b/doc/user/discussions/img/mr_review_start.png diff --git a/doc/user/discussions/img/mr_review_unresolve.png b/doc/user/discussions/img/mr_review_unresolve.png Binary files differindex 3441efc1572..4bef38f7808 100644 --- a/doc/user/discussions/img/mr_review_unresolve.png +++ b/doc/user/discussions/img/mr_review_unresolve.png diff --git a/doc/user/discussions/img/mr_review_unresolve2.png b/doc/user/discussions/img/mr_review_unresolve2.png Binary files differindex a824b806e4a..79da61bb556 100644 --- a/doc/user/discussions/img/mr_review_unresolve2.png +++ b/doc/user/discussions/img/mr_review_unresolve2.png diff --git a/doc/user/discussions/img/multi-line-suggestion-preview.png b/doc/user/discussions/img/multi-line-suggestion-preview.png Binary files differindex 4288d0ba034..476c50b9098 100644 --- a/doc/user/discussions/img/multi-line-suggestion-preview.png +++ b/doc/user/discussions/img/multi-line-suggestion-preview.png diff --git a/doc/user/discussions/img/multi-line-suggestion-syntax.png b/doc/user/discussions/img/multi-line-suggestion-syntax.png Binary files differindex df0c99b84ef..80424d1f056 100644 --- a/doc/user/discussions/img/multi-line-suggestion-syntax.png +++ b/doc/user/discussions/img/multi-line-suggestion-syntax.png diff --git a/doc/user/discussions/img/new_issue_for_thread.png b/doc/user/discussions/img/new_issue_for_thread.png Binary files differindex 2264da0b5b5..28b76adf7fe 100644 --- a/doc/user/discussions/img/new_issue_for_thread.png +++ b/doc/user/discussions/img/new_issue_for_thread.png diff --git a/doc/user/discussions/img/onion_skin_view.png b/doc/user/discussions/img/onion_skin_view.png Binary files differindex 9bb4428184e..81bb4a2c85a 100644 --- a/doc/user/discussions/img/onion_skin_view.png +++ b/doc/user/discussions/img/onion_skin_view.png diff --git a/doc/user/discussions/img/only_allow_merge_if_all_threads_are_resolved.png b/doc/user/discussions/img/only_allow_merge_if_all_threads_are_resolved.png Binary files differindex 9314e3a6490..bd0aaca79b2 100644 --- a/doc/user/discussions/img/only_allow_merge_if_all_threads_are_resolved.png +++ b/doc/user/discussions/img/only_allow_merge_if_all_threads_are_resolved.png diff --git a/doc/user/discussions/img/pending_review_comment.png b/doc/user/discussions/img/pending_review_comment.png Binary files differindex 812e4ac966a..70a66b3f4f0 100644 --- a/doc/user/discussions/img/pending_review_comment.png +++ b/doc/user/discussions/img/pending_review_comment.png diff --git a/doc/user/discussions/img/preview_issue_for_thread.png b/doc/user/discussions/img/preview_issue_for_thread.png Binary files differindex 1517902c61c..a9d7ab598be 100644 --- a/doc/user/discussions/img/preview_issue_for_thread.png +++ b/doc/user/discussions/img/preview_issue_for_thread.png diff --git a/doc/user/discussions/img/preview_issue_for_threads.png b/doc/user/discussions/img/preview_issue_for_threads.png Binary files differindex 8359ab3143c..8757decb178 100644 --- a/doc/user/discussions/img/preview_issue_for_threads.png +++ b/doc/user/discussions/img/preview_issue_for_threads.png diff --git a/doc/user/discussions/img/reply_to_comment_button.png b/doc/user/discussions/img/reply_to_comment_button.png Binary files differindex d362b19785c..d327d1c3e27 100644 --- a/doc/user/discussions/img/reply_to_comment_button.png +++ b/doc/user/discussions/img/reply_to_comment_button.png diff --git a/doc/user/discussions/img/resolve_comment_button.png b/doc/user/discussions/img/resolve_comment_button.png Binary files differindex 0319ec999fd..0a3ed03a69c 100644 --- a/doc/user/discussions/img/resolve_comment_button.png +++ b/doc/user/discussions/img/resolve_comment_button.png diff --git a/doc/user/discussions/img/resolve_thread_button.png b/doc/user/discussions/img/resolve_thread_button.png Binary files differindex 873c302f570..ca0a3e50550 100644 --- a/doc/user/discussions/img/resolve_thread_button.png +++ b/doc/user/discussions/img/resolve_thread_button.png diff --git a/doc/user/discussions/img/resolve_thread_issue_notice.png b/doc/user/discussions/img/resolve_thread_issue_notice.png Binary files differindex c2a8fdebee7..30a65b8fbd4 100644 --- a/doc/user/discussions/img/resolve_thread_issue_notice.png +++ b/doc/user/discussions/img/resolve_thread_issue_notice.png diff --git a/doc/user/discussions/img/resolve_thread_open_issue.png b/doc/user/discussions/img/resolve_thread_open_issue.png Binary files differindex be2a4365297..2dd4ea3cb1b 100644 --- a/doc/user/discussions/img/resolve_thread_open_issue.png +++ b/doc/user/discussions/img/resolve_thread_open_issue.png diff --git a/doc/user/discussions/img/review_comment_quickactions.png b/doc/user/discussions/img/review_comment_quickactions.png Binary files differindex df5c4dd0fcc..276def6381f 100644 --- a/doc/user/discussions/img/review_comment_quickactions.png +++ b/doc/user/discussions/img/review_comment_quickactions.png diff --git a/doc/user/discussions/img/review_preview.png b/doc/user/discussions/img/review_preview.png Binary files differindex 1b91506b477..e69a58dbb91 100644 --- a/doc/user/discussions/img/review_preview.png +++ b/doc/user/discussions/img/review_preview.png diff --git a/doc/user/discussions/img/swipe_view.png b/doc/user/discussions/img/swipe_view.png Binary files differindex 287d52a0811..e6f5e5053af 100644 --- a/doc/user/discussions/img/swipe_view.png +++ b/doc/user/discussions/img/swipe_view.png diff --git a/doc/user/discussions/img/thread_view.png b/doc/user/discussions/img/thread_view.png Binary files differindex 8c1fd9d5acf..e2db44aa604 100644 --- a/doc/user/discussions/img/thread_view.png +++ b/doc/user/discussions/img/thread_view.png diff --git a/doc/user/discussions/img/threads_resolved.png b/doc/user/discussions/img/threads_resolved.png Binary files differindex 6ac815cf874..ffb1233f2ee 100644 --- a/doc/user/discussions/img/threads_resolved.png +++ b/doc/user/discussions/img/threads_resolved.png diff --git a/doc/user/discussions/img/two_up_view.png b/doc/user/discussions/img/two_up_view.png Binary files differindex 062a96723dd..3b6ddfbe1be 100644 --- a/doc/user/discussions/img/two_up_view.png +++ b/doc/user/discussions/img/two_up_view.png diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md index e6c27c33654..928950126da 100644 --- a/doc/user/gitlab_com/index.md +++ b/doc/user/gitlab_com/index.md @@ -316,7 +316,8 @@ with details, such as the affected IP address. ### HAProxy API throttle -GitLab.com responds with HTTP status code 429 to API requests over 10 requests +GitLab.com responds with HTTP status code `429` to API requests that exceed 10 +requests per second per IP address. The following example headers are included for all API requests: @@ -335,10 +336,12 @@ Source: ### Rack Attack initializer +Details of rate limits enforced by [Rack Attack](../../security/rack_attack.md). + #### Protected paths throttle -GitLab.com responds with HTTP status code 429 to POST requests at protected -paths over 10 requests per **minute** per IP address. +GitLab.com responds with HTTP status code `429` to POST requests at protected +paths that exceed 10 requests per **minute** per IP address. See the source below for which paths are protected. This includes user creation, user confirmation, user sign in, and password reset. diff --git a/doc/user/group/bulk_editing/img/bulk-editing.png b/doc/user/group/bulk_editing/img/bulk-editing.png Binary files differindex d08503dc312..8e2bd265054 100644 --- a/doc/user/group/bulk_editing/img/bulk-editing.png +++ b/doc/user/group/bulk_editing/img/bulk-editing.png diff --git a/doc/user/group/epics/img/button_reopen_epic.png b/doc/user/group/epics/img/button_reopen_epic.png Binary files differindex 7a953189270..9d1be88549d 100644 --- a/doc/user/group/epics/img/button_reopen_epic.png +++ b/doc/user/group/epics/img/button_reopen_epic.png diff --git a/doc/user/group/epics/img/containing_epic.png b/doc/user/group/epics/img/containing_epic.png Binary files differindex 5ed693e6d6a..dc13d55e2bc 100644 --- a/doc/user/group/epics/img/containing_epic.png +++ b/doc/user/group/epics/img/containing_epic.png diff --git a/doc/user/group/epics/img/epic_view.png b/doc/user/group/epics/img/epic_view.png Binary files differindex dbda98e4351..c55d302ec29 100644 --- a/doc/user/group/epics/img/epic_view.png +++ b/doc/user/group/epics/img/epic_view.png diff --git a/doc/user/group/img/group_file_template_dropdown.png b/doc/user/group/img/group_file_template_dropdown.png Binary files differindex d9caae1a223..f0586772218 100644 --- a/doc/user/group/img/group_file_template_dropdown.png +++ b/doc/user/group/img/group_file_template_dropdown.png diff --git a/doc/user/group/img/group_file_template_settings.png b/doc/user/group/img/group_file_template_settings.png Binary files differindex ca42f7726db..5e07974bc86 100644 --- a/doc/user/group/img/group_file_template_settings.png +++ b/doc/user/group/img/group_file_template_settings.png diff --git a/doc/user/group/insights/img/insights_example_stacked_bar_chart.png b/doc/user/group/insights/img/insights_example_stacked_bar_chart.png Binary files differindex 791d0e4bcdf..0e338b99e4c 100644 --- a/doc/user/group/insights/img/insights_example_stacked_bar_chart.png +++ b/doc/user/group/insights/img/insights_example_stacked_bar_chart.png diff --git a/doc/user/group/insights/img/insights_group_configuration.png b/doc/user/group/insights/img/insights_group_configuration.png Binary files differindex 0af0073e448..d181a1e94c3 100644 --- a/doc/user/group/insights/img/insights_group_configuration.png +++ b/doc/user/group/insights/img/insights_group_configuration.png diff --git a/doc/user/group/insights/img/insights_sidebar_link.png b/doc/user/group/insights/img/insights_sidebar_link.png Binary files differindex 64bbd1fc4d3..f7b0c2daae3 100644 --- a/doc/user/group/insights/img/insights_sidebar_link.png +++ b/doc/user/group/insights/img/insights_sidebar_link.png diff --git a/doc/user/group/roadmap/img/roadmap_view.png b/doc/user/group/roadmap/img/roadmap_view.png Binary files differindex ff41a2e0441..2be3849ba1b 100644 --- a/doc/user/group/roadmap/img/roadmap_view.png +++ b/doc/user/group/roadmap/img/roadmap_view.png diff --git a/doc/user/group/saml_sso/img/group_saml_configuration_information.png b/doc/user/group/saml_sso/img/group_saml_configuration_information.png Binary files differindex 98b83d0cb0f..e03c50ceb01 100644 --- a/doc/user/group/saml_sso/img/group_saml_configuration_information.png +++ b/doc/user/group/saml_sso/img/group_saml_configuration_information.png diff --git a/doc/user/group/saml_sso/img/group_saml_settings.png b/doc/user/group/saml_sso/img/group_saml_settings.png Binary files differindex 8c5dbe36f98..487be4faeba 100644 --- a/doc/user/group/saml_sso/img/group_saml_settings.png +++ b/doc/user/group/saml_sso/img/group_saml_settings.png diff --git a/doc/user/group/saml_sso/img/scim_advanced.png b/doc/user/group/saml_sso/img/scim_advanced.png Binary files differindex 3b70e3fbe83..c9e095dc89a 100644 --- a/doc/user/group/saml_sso/img/scim_advanced.png +++ b/doc/user/group/saml_sso/img/scim_advanced.png diff --git a/doc/user/group/saml_sso/img/scim_attribute_mapping.png b/doc/user/group/saml_sso/img/scim_attribute_mapping.png Binary files differindex dad459d8c28..933d8fb6f36 100644 --- a/doc/user/group/saml_sso/img/scim_attribute_mapping.png +++ b/doc/user/group/saml_sso/img/scim_attribute_mapping.png diff --git a/doc/user/group/saml_sso/img/scim_name_identifier_mapping.png b/doc/user/group/saml_sso/img/scim_name_identifier_mapping.png Binary files differindex 85e5648816e..f9c63970f16 100644 --- a/doc/user/group/saml_sso/img/scim_name_identifier_mapping.png +++ b/doc/user/group/saml_sso/img/scim_name_identifier_mapping.png diff --git a/doc/user/group/saml_sso/img/scim_provisioning_status.png b/doc/user/group/saml_sso/img/scim_provisioning_status.png Binary files differindex 4b8887b5418..41466ec9276 100644 --- a/doc/user/group/saml_sso/img/scim_provisioning_status.png +++ b/doc/user/group/saml_sso/img/scim_provisioning_status.png diff --git a/doc/user/group/saml_sso/img/scim_token.png b/doc/user/group/saml_sso/img/scim_token.png Binary files differindex 7eb52bf6ea2..bf9347716e9 100644 --- a/doc/user/group/saml_sso/img/scim_token.png +++ b/doc/user/group/saml_sso/img/scim_token.png diff --git a/doc/user/group/saml_sso/img/unlink_group_saml.png b/doc/user/group/saml_sso/img/unlink_group_saml.png Binary files differindex 0561443b5f4..9d53a9bf407 100644 --- a/doc/user/group/saml_sso/img/unlink_group_saml.png +++ b/doc/user/group/saml_sso/img/unlink_group_saml.png diff --git a/doc/user/operations_dashboard/img/index_operations_dashboard_top_bar_icon.png b/doc/user/operations_dashboard/img/index_operations_dashboard_top_bar_icon.png Binary files differindex 9d6a509ea72..d4db5e88672 100644 --- a/doc/user/operations_dashboard/img/index_operations_dashboard_top_bar_icon.png +++ b/doc/user/operations_dashboard/img/index_operations_dashboard_top_bar_icon.png diff --git a/doc/user/operations_dashboard/img/index_operations_dashboard_with_projects.png b/doc/user/operations_dashboard/img/index_operations_dashboard_with_projects.png Binary files differindex ee33eee8134..7dbec81c18a 100644 --- a/doc/user/operations_dashboard/img/index_operations_dashboard_with_projects.png +++ b/doc/user/operations_dashboard/img/index_operations_dashboard_with_projects.png diff --git a/doc/user/profile/img/active_sessions_list.png b/doc/user/profile/img/active_sessions_list.png Binary files differindex 1e242ac4710..41173c7eee5 100644 --- a/doc/user/profile/img/active_sessions_list.png +++ b/doc/user/profile/img/active_sessions_list.png diff --git a/doc/user/project/clusters/img/k8s_cluster_monitoring.png b/doc/user/project/clusters/img/k8s_cluster_monitoring.png Binary files differindex e449893a606..0a8c5043c65 100644 --- a/doc/user/project/clusters/img/k8s_cluster_monitoring.png +++ b/doc/user/project/clusters/img/k8s_cluster_monitoring.png diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index f0d80dad94f..7dfd0d04637 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -384,13 +384,9 @@ NOTE: **Note:** [RBAC](#rbac-cluster-resources) is recommended and the GitLab default. GitLab creates the necessary service accounts and privileges to install and run -[GitLab managed applications](#installing-applications). When GitLab creates the cluster: - -- A `gitlab` service account with `cluster-admin` privileges is created in the `default` namespace - to manage the newly created cluster. -- A project service account with [`edit` - privileges](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) - is created in the GitLab-created project namespace for [deployment jobs](#deployment-variables). +[GitLab managed applications](#installing-applications). When GitLab creates the cluster, +a `gitlab` service account with `cluster-admin` privileges is created in the `default` namespace +to manage the newly created cluster. NOTE: **Note:** Restricted service account for deployment was [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/51716) in GitLab 11.5. @@ -412,32 +408,37 @@ The resources created by GitLab differ depending on the type of cluster. GitLab creates the following resources for ABAC clusters. -| Name | Type | Details | Created when | -|:------------------|:---------------------|:----------------------------------|:---------------------------| -| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster | -| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster | -| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | -| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller | -| Project namespace | `ServiceAccount` | Uses namespace of Project | Deploying to a cluster | -| Project namespace | `Secret` | Token for project ServiceAccount | Deploying to a cluster | +| Name | Type | Details | Created when | +|:----------------------|:---------------------|:-------------------------------------|:---------------------------| +| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster | +| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster | +| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | +| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller | +| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster | +| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster | +| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster | #### RBAC cluster resources GitLab creates the following resources for RBAC clusters. -| Name | Type | Details | Created when | -|:------------------|:---------------------|:-----------------------------------------------------------------------------------------------------------|:---------------------------| -| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster | -| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Creating a new GKE Cluster | -| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster | -| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | -| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller | -| Project namespace | `ServiceAccount` | Uses namespace of Project | Deploying to a cluster | -| Project namespace | `Secret` | Token for project ServiceAccount | Deploying to a cluster | -| Project namespace | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Deploying to a cluster | +| Name | Type | Details | Created when | +|:----------------------|:---------------------|:-----------------------------------------------------------------------------------------------------------|:---------------------------| +| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster | +| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Creating a new GKE Cluster | +| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster | +| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | +| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller | +| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster | +| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster | +| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster | +| Environment namespace | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Deploying to a cluster | + +NOTE: **Note:** +Environment-specific resources are only created if your cluster is [managed by GitLab](#gitlab-managed-clusters). NOTE: **Note:** -Project-specific resources are only created if your cluster is [managed by GitLab](#gitlab-managed-clusters). +If your project was created before GitLab 12.2 it will use a single namespace for all project environments. #### Security of GitLab Runners @@ -640,8 +641,8 @@ GitLab CI/CD build environment. | Variable | Description | | -------- | ----------- | | `KUBE_URL` | Equal to the API URL. | -| `KUBE_TOKEN` | The Kubernetes token of the [project service account](#access-controls). | -| `KUBE_NAMESPACE` | The Kubernetes namespace is auto-generated if not specified. The default value is `<project_name>-<project_id>`. You can overwrite it to use different one if needed, otherwise the `KUBE_NAMESPACE` variable will receive the default value. | +| `KUBE_TOKEN` | The Kubernetes token of the [environment service account](#access-controls). | +| `KUBE_NAMESPACE` | The Kubernetes namespace is auto-generated if not specified. The default value is `<project_name>-<project_id>-<environment>`. You can overwrite it to use different one if needed, otherwise the `KUBE_NAMESPACE` variable will receive the default value. | | `KUBE_CA_PEM_FILE` | Path to a file containing PEM data. Only present if a custom CA bundle was specified. | | `KUBE_CA_PEM` | (**deprecated**) Raw PEM data. Only if a custom CA bundle was specified. | | `KUBECONFIG` | Path to a file containing `kubeconfig` for this deployment. CA bundle would be embedded if specified. This config also embeds the same token defined in `KUBE_TOKEN` so you likely will only need this variable. This variable name is also automatically picked up by `kubectl` so you won't actually need to reference it explicitly if using `kubectl`. | diff --git a/doc/user/project/clusters/serverless/img/dns-entry.png b/doc/user/project/clusters/serverless/img/dns-entry.png Binary files differindex 351e40b77d5..7b5d6497f0e 100644 --- a/doc/user/project/clusters/serverless/img/dns-entry.png +++ b/doc/user/project/clusters/serverless/img/dns-entry.png diff --git a/doc/user/project/clusters/serverless/img/function-details-loaded.png b/doc/user/project/clusters/serverless/img/function-details-loaded.png Binary files differindex 34465c5c087..2f0d61f8032 100644 --- a/doc/user/project/clusters/serverless/img/function-details-loaded.png +++ b/doc/user/project/clusters/serverless/img/function-details-loaded.png diff --git a/doc/user/project/clusters/serverless/img/function-endpoint.png b/doc/user/project/clusters/serverless/img/function-endpoint.png Binary files differindex f3c7ae7a00d..a38fe2cb6c2 100644 --- a/doc/user/project/clusters/serverless/img/function-endpoint.png +++ b/doc/user/project/clusters/serverless/img/function-endpoint.png diff --git a/doc/user/project/clusters/serverless/img/function-execution.png b/doc/user/project/clusters/serverless/img/function-execution.png Binary files differindex 93b0b6d802d..f60dd277081 100644 --- a/doc/user/project/clusters/serverless/img/function-execution.png +++ b/doc/user/project/clusters/serverless/img/function-execution.png diff --git a/doc/user/project/clusters/serverless/img/install-knative.png b/doc/user/project/clusters/serverless/img/install-knative.png Binary files differindex ecc2f8fb481..1dc830848f2 100644 --- a/doc/user/project/clusters/serverless/img/install-knative.png +++ b/doc/user/project/clusters/serverless/img/install-knative.png diff --git a/doc/user/project/clusters/serverless/img/serverless-page.png b/doc/user/project/clusters/serverless/img/serverless-page.png Binary files differindex a872fda7740..8dce3cb1f70 100644 --- a/doc/user/project/clusters/serverless/img/serverless-page.png +++ b/doc/user/project/clusters/serverless/img/serverless-page.png diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md index 92ad49e9448..bcf9a677a40 100644 --- a/doc/user/project/clusters/serverless/index.md +++ b/doc/user/project/clusters/serverless/index.md @@ -434,7 +434,7 @@ The instructions below relate to installing and running Certbot on a Linux serve ./certbot-auto certonly --manual --preferred-challenges dns -d '*.<namespace>.example.com' ``` - Where `<namespace>` is the namespace created by GitLab for your serverless project (composed of `<projectname+id>`) and + Where `<namespace>` is the namespace created by GitLab for your serverless project (composed of `<project_name>-<project_id>-<environment>`) and `example.com` is the domain being used for your project. If you are unsure what the namespace of your project is, navigate to the **Operations > Serverless** page of your project and inspect the endpoint provided for your function/app. diff --git a/doc/user/project/deploy_tokens/img/deploy_tokens.png b/doc/user/project/deploy_tokens/img/deploy_tokens.png Binary files differindex 421aa1ab3e5..493de8e0fce 100644 --- a/doc/user/project/deploy_tokens/img/deploy_tokens.png +++ b/doc/user/project/deploy_tokens/img/deploy_tokens.png diff --git a/doc/user/project/img/cycle_analytics_landing_page.png b/doc/user/project/img/cycle_analytics_landing_page.png Binary files differindex cf46098b9a4..c0c07e84a82 100644 --- a/doc/user/project/img/cycle_analytics_landing_page.png +++ b/doc/user/project/img/cycle_analytics_landing_page.png diff --git a/doc/user/project/img/deploy_boards_kubernetes_label.png b/doc/user/project/img/deploy_boards_kubernetes_label.png Binary files differindex 19785c74d07..130ff2caa8a 100644 --- a/doc/user/project/img/deploy_boards_kubernetes_label.png +++ b/doc/user/project/img/deploy_boards_kubernetes_label.png diff --git a/doc/user/project/img/file_lock.png b/doc/user/project/img/file_lock.png Binary files differindex 82699a12ffd..e881442630b 100644 --- a/doc/user/project/img/file_lock.png +++ b/doc/user/project/img/file_lock.png diff --git a/doc/user/project/img/file_lock_merge_request_error_message.png b/doc/user/project/img/file_lock_merge_request_error_message.png Binary files differindex 4ef04b15bef..64bcc86ac0d 100644 --- a/doc/user/project/img/file_lock_merge_request_error_message.png +++ b/doc/user/project/img/file_lock_merge_request_error_message.png diff --git a/doc/user/project/img/file_lock_repository_view.png b/doc/user/project/img/file_lock_repository_view.png Binary files differindex a2cab0decab..ced14198da9 100644 --- a/doc/user/project/img/file_lock_repository_view.png +++ b/doc/user/project/img/file_lock_repository_view.png diff --git a/doc/user/project/img/issue_boards_multiple.png b/doc/user/project/img/issue_boards_multiple.png Binary files differindex 4b1a8356dc9..e6183360610 100644 --- a/doc/user/project/img/issue_boards_multiple.png +++ b/doc/user/project/img/issue_boards_multiple.png diff --git a/doc/user/project/img/labels_default_v12_1.png b/doc/user/project/img/labels_default_v12_1.png Binary files differindex 4a0a6ba9ce0..b36b5dac80b 100644 --- a/doc/user/project/img/labels_default_v12_1.png +++ b/doc/user/project/img/labels_default_v12_1.png diff --git a/doc/user/project/img/labels_delete_v12_1.png b/doc/user/project/img/labels_delete_v12_1.png Binary files differindex 2e0ea934519..566e0519fbe 100644 --- a/doc/user/project/img/labels_delete_v12_1.png +++ b/doc/user/project/img/labels_delete_v12_1.png diff --git a/doc/user/project/img/labels_epic_sidebar_v12_1.png b/doc/user/project/img/labels_epic_sidebar_v12_1.png Binary files differindex 7e05c6d1ce4..13fbab33e26 100644 --- a/doc/user/project/img/labels_epic_sidebar_v12_1.png +++ b/doc/user/project/img/labels_epic_sidebar_v12_1.png diff --git a/doc/user/project/img/labels_generate_default_v12_1.png b/doc/user/project/img/labels_generate_default_v12_1.png Binary files differindex 48adc9a5699..cbdda2ab4dd 100644 --- a/doc/user/project/img/labels_generate_default_v12_1.png +++ b/doc/user/project/img/labels_generate_default_v12_1.png diff --git a/doc/user/project/img/labels_group_issues_v12_1.png b/doc/user/project/img/labels_group_issues_v12_1.png Binary files differindex bfe425f20ac..3f8f93c1dfd 100644 --- a/doc/user/project/img/labels_group_issues_v12_1.png +++ b/doc/user/project/img/labels_group_issues_v12_1.png diff --git a/doc/user/project/img/labels_key_value_v12_1.png b/doc/user/project/img/labels_key_value_v12_1.png Binary files differindex 81d5c416c95..52906b7b458 100644 --- a/doc/user/project/img/labels_key_value_v12_1.png +++ b/doc/user/project/img/labels_key_value_v12_1.png diff --git a/doc/user/project/img/labels_list_v12_1.png b/doc/user/project/img/labels_list_v12_1.png Binary files differindex c414ab42fbc..47359d05f7f 100644 --- a/doc/user/project/img/labels_list_v12_1.png +++ b/doc/user/project/img/labels_list_v12_1.png diff --git a/doc/user/project/img/labels_prioritized_v12_1.png b/doc/user/project/img/labels_prioritized_v12_1.png Binary files differindex 8ea69949d8e..512c5d59a5a 100644 --- a/doc/user/project/img/labels_prioritized_v12_1.png +++ b/doc/user/project/img/labels_prioritized_v12_1.png diff --git a/doc/user/project/img/labels_promotion_v12_1.png b/doc/user/project/img/labels_promotion_v12_1.png Binary files differindex 238d50981ae..7cd8ff24e02 100644 --- a/doc/user/project/img/labels_promotion_v12_1.png +++ b/doc/user/project/img/labels_promotion_v12_1.png diff --git a/doc/user/project/img/labels_subscriptions_v12_1.png b/doc/user/project/img/labels_subscriptions_v12_1.png Binary files differindex 57c437ac8a4..fa83b7db414 100644 --- a/doc/user/project/img/labels_subscriptions_v12_1.png +++ b/doc/user/project/img/labels_subscriptions_v12_1.png diff --git a/doc/user/project/img/service_desk_disabled.png b/doc/user/project/img/service_desk_disabled.png Binary files differindex 3ae64dcbe96..edae7e76986 100644 --- a/doc/user/project/img/service_desk_disabled.png +++ b/doc/user/project/img/service_desk_disabled.png diff --git a/doc/user/project/img/service_desk_enabled.png b/doc/user/project/img/service_desk_enabled.png Binary files differindex 329348e4b52..9c143ff58cd 100644 --- a/doc/user/project/img/service_desk_enabled.png +++ b/doc/user/project/img/service_desk_enabled.png diff --git a/doc/user/project/img/service_desk_issue_tracker.png b/doc/user/project/img/service_desk_issue_tracker.png Binary files differindex 485751fab0a..02d18c9debb 100644 --- a/doc/user/project/img/service_desk_issue_tracker.png +++ b/doc/user/project/img/service_desk_issue_tracker.png diff --git a/doc/user/project/import/tfs.md b/doc/user/project/import/tfs.md index b4597a4da60..01bbb7e6ffd 100644 --- a/doc/user/project/import/tfs.md +++ b/doc/user/project/import/tfs.md @@ -1,6 +1,6 @@ # Migrating from TFS -[TFS](https://visualstudio.microsoft.com/tfs/) is a set of tools developed by Microsoft +[TFS](https://azure.microsoft.com/en-us/services/devops/server/) is a set of tools developed by Microsoft which also includes a centralized version control system (TFVC) similar to Git. In this document, we emphasize on the TFVC to Git migration. diff --git a/doc/user/project/insights/img/insights_example_bar_chart.png b/doc/user/project/insights/img/insights_example_bar_chart.png Binary files differindex eb96eb4a90f..5fd24265b32 100644 --- a/doc/user/project/insights/img/insights_example_bar_chart.png +++ b/doc/user/project/insights/img/insights_example_bar_chart.png diff --git a/doc/user/project/insights/img/insights_example_bar_time_series_chart.png b/doc/user/project/insights/img/insights_example_bar_time_series_chart.png Binary files differindex 28aa81939d8..2e32df3e2b1 100644 --- a/doc/user/project/insights/img/insights_example_bar_time_series_chart.png +++ b/doc/user/project/insights/img/insights_example_bar_time_series_chart.png diff --git a/doc/user/project/insights/img/insights_example_line_chart.png b/doc/user/project/insights/img/insights_example_line_chart.png Binary files differindex 131dbedd35e..9460b104339 100644 --- a/doc/user/project/insights/img/insights_example_line_chart.png +++ b/doc/user/project/insights/img/insights_example_line_chart.png diff --git a/doc/user/project/insights/img/insights_example_pie_chart.png b/doc/user/project/insights/img/insights_example_pie_chart.png Binary files differindex 518ed7338f9..3480bce6738 100644 --- a/doc/user/project/insights/img/insights_example_pie_chart.png +++ b/doc/user/project/insights/img/insights_example_pie_chart.png diff --git a/doc/user/project/insights/img/insights_example_stacked_bar_chart.png b/doc/user/project/insights/img/insights_example_stacked_bar_chart.png Binary files differindex aafec4b394e..a3fb50488f5 100644 --- a/doc/user/project/insights/img/insights_example_stacked_bar_chart.png +++ b/doc/user/project/insights/img/insights_example_stacked_bar_chart.png diff --git a/doc/user/project/insights/img/insights_sidebar_link.png b/doc/user/project/insights/img/insights_sidebar_link.png Binary files differindex aadb5745992..9fc449baf68 100644 --- a/doc/user/project/insights/img/insights_sidebar_link.png +++ b/doc/user/project/insights/img/insights_sidebar_link.png diff --git a/doc/user/project/insights/img/project_insights.png b/doc/user/project/insights/img/project_insights.png Binary files differindex 2d0292dda54..83674c94110 100644 --- a/doc/user/project/insights/img/project_insights.png +++ b/doc/user/project/insights/img/project_insights.png diff --git a/doc/user/project/integrations/img/github_configuration.png b/doc/user/project/integrations/img/github_configuration.png Binary files differindex 9f2d47921c7..5798b826681 100644 --- a/doc/user/project/integrations/img/github_configuration.png +++ b/doc/user/project/integrations/img/github_configuration.png diff --git a/doc/user/project/integrations/img/jira_add_user_to_group.png b/doc/user/project/integrations/img/jira_add_user_to_group.png Binary files differindex d8cf541a81e..b63a851a987 100644 --- a/doc/user/project/integrations/img/jira_add_user_to_group.png +++ b/doc/user/project/integrations/img/jira_add_user_to_group.png diff --git a/doc/user/project/integrations/img/jira_added_user_to_group.png b/doc/user/project/integrations/img/jira_added_user_to_group.png Binary files differindex b3e29a65d6e..f5120a8d42e 100644 --- a/doc/user/project/integrations/img/jira_added_user_to_group.png +++ b/doc/user/project/integrations/img/jira_added_user_to_group.png diff --git a/doc/user/project/integrations/img/jira_api_token.png b/doc/user/project/integrations/img/jira_api_token.png Binary files differindex 29689271bf7..d9d37713a4d 100644 --- a/doc/user/project/integrations/img/jira_api_token.png +++ b/doc/user/project/integrations/img/jira_api_token.png diff --git a/doc/user/project/integrations/img/jira_api_token_menu.png b/doc/user/project/integrations/img/jira_api_token_menu.png Binary files differindex 1aca1d78f36..a10a59a243d 100644 --- a/doc/user/project/integrations/img/jira_api_token_menu.png +++ b/doc/user/project/integrations/img/jira_api_token_menu.png diff --git a/doc/user/project/integrations/img/jira_create_new_group.png b/doc/user/project/integrations/img/jira_create_new_group.png Binary files differindex 84be3a94a45..4ab7a5eae4e 100644 --- a/doc/user/project/integrations/img/jira_create_new_group.png +++ b/doc/user/project/integrations/img/jira_create_new_group.png diff --git a/doc/user/project/integrations/img/jira_create_new_user.png b/doc/user/project/integrations/img/jira_create_new_user.png Binary files differindex 8460dc98ef9..c74933298e3 100644 --- a/doc/user/project/integrations/img/jira_create_new_user.png +++ b/doc/user/project/integrations/img/jira_create_new_user.png diff --git a/doc/user/project/integrations/img/jira_group_access.png b/doc/user/project/integrations/img/jira_group_access.png Binary files differindex 58cf114bd55..e33f2eed242 100644 --- a/doc/user/project/integrations/img/jira_group_access.png +++ b/doc/user/project/integrations/img/jira_group_access.png diff --git a/doc/user/project/integrations/img/jira_issue_reference.png b/doc/user/project/integrations/img/jira_issue_reference.png Binary files differindex a3e80c1b054..db8bc4f0bb9 100644 --- a/doc/user/project/integrations/img/jira_issue_reference.png +++ b/doc/user/project/integrations/img/jira_issue_reference.png diff --git a/doc/user/project/integrations/img/jira_merge_request_close.png b/doc/user/project/integrations/img/jira_merge_request_close.png Binary files differindex 1c089c94207..9a176daf5f4 100644 --- a/doc/user/project/integrations/img/jira_merge_request_close.png +++ b/doc/user/project/integrations/img/jira_merge_request_close.png diff --git a/doc/user/project/integrations/img/jira_service_page.png b/doc/user/project/integrations/img/jira_service_page.png Binary files differindex 80dd65ea24e..76fd5f4641c 100644 --- a/doc/user/project/integrations/img/jira_service_page.png +++ b/doc/user/project/integrations/img/jira_service_page.png diff --git a/doc/user/project/integrations/img/jira_user_management_link.png b/doc/user/project/integrations/img/jira_user_management_link.png Binary files differindex 43ef18da6c8..caecd1d71fc 100644 --- a/doc/user/project/integrations/img/jira_user_management_link.png +++ b/doc/user/project/integrations/img/jira_user_management_link.png diff --git a/doc/user/project/integrations/img/mattermost_configuration.png b/doc/user/project/integrations/img/mattermost_configuration.png Binary files differindex 75ef0310f2d..6abf5c5c8d6 100644 --- a/doc/user/project/integrations/img/mattermost_configuration.png +++ b/doc/user/project/integrations/img/mattermost_configuration.png diff --git a/doc/user/project/integrations/img/prometheus_dashboard_area_panel_type.png b/doc/user/project/integrations/img/prometheus_dashboard_area_panel_type.png Binary files differindex 7260b11f07b..9fdb6dfddac 100644 --- a/doc/user/project/integrations/img/prometheus_dashboard_area_panel_type.png +++ b/doc/user/project/integrations/img/prometheus_dashboard_area_panel_type.png diff --git a/doc/user/project/integrations/img/prometheus_dashboard_single_stat_panel_type.png b/doc/user/project/integrations/img/prometheus_dashboard_single_stat_panel_type.png Binary files differindex ce4c54f909d..2d7dfb27b49 100644 --- a/doc/user/project/integrations/img/prometheus_dashboard_single_stat_panel_type.png +++ b/doc/user/project/integrations/img/prometheus_dashboard_single_stat_panel_type.png diff --git a/doc/user/project/integrations/img/prometheus_service_alerts.png b/doc/user/project/integrations/img/prometheus_service_alerts.png Binary files differindex a81dfe7da14..609c5e5196c 100644 --- a/doc/user/project/integrations/img/prometheus_service_alerts.png +++ b/doc/user/project/integrations/img/prometheus_service_alerts.png diff --git a/doc/user/project/integrations/img/slack_configuration.png b/doc/user/project/integrations/img/slack_configuration.png Binary files differindex a14d2969488..10d2cda6dc7 100644 --- a/doc/user/project/integrations/img/slack_configuration.png +++ b/doc/user/project/integrations/img/slack_configuration.png diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md index 2327fa84998..bffbcb544e3 100644 --- a/doc/user/project/issues/design_management.md +++ b/doc/user/project/issues/design_management.md @@ -3,7 +3,7 @@ > [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/660) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2. CAUTION: **Warning:** -This an __alpha__ feature and is subject to change at any time without +This an **alpha** feature and is subject to change at any time without prior notice. ## Overview @@ -56,3 +56,14 @@ of the design, and will replace the previous version. Images on the Design Management page can be enlarged by clicking on them. +## Adding annotations to designs + +When a design image is displayed, you can add annotations to it by clicking on +the image. A badge is added to the image and a form is displayed to start a new +discussion. For example: + +![Starting a new discussion on design](img/adding_note_to_design_1.png) + +When submitted, the form saves a badge linked to the discussion on the image. Different discussions have different badge numbers. For example: + +![Discussions on design annotations](img/adding_note_to_design_2.png) diff --git a/doc/user/project/issues/img/adding_note_to_design_1.png b/doc/user/project/issues/img/adding_note_to_design_1.png Binary files differnew file mode 100644 index 00000000000..aa50bbb69ce --- /dev/null +++ b/doc/user/project/issues/img/adding_note_to_design_1.png diff --git a/doc/user/project/issues/img/adding_note_to_design_2.png b/doc/user/project/issues/img/adding_note_to_design_2.png Binary files differnew file mode 100644 index 00000000000..37cefeb1a15 --- /dev/null +++ b/doc/user/project/issues/img/adding_note_to_design_2.png diff --git a/doc/user/project/issues/img/comment-or-discussion.png b/doc/user/project/issues/img/comment-or-discussion.png Binary files differindex ccecc9fa39f..a29014c984c 100644 --- a/doc/user/project/issues/img/comment-or-discussion.png +++ b/doc/user/project/issues/img/comment-or-discussion.png diff --git a/doc/user/project/issues/img/confidential_mr_branch_dropdown_v12_1.png b/doc/user/project/issues/img/confidential_mr_branch_dropdown_v12_1.png Binary files differindex 7c24226a6c4..1f4ad5c42bb 100644 --- a/doc/user/project/issues/img/confidential_mr_branch_dropdown_v12_1.png +++ b/doc/user/project/issues/img/confidential_mr_branch_dropdown_v12_1.png diff --git a/doc/user/project/issues/img/confidential_mr_dropdown_v12_1.png b/doc/user/project/issues/img/confidential_mr_dropdown_v12_1.png Binary files differindex d6d391c6dd9..7b7bd599a71 100644 --- a/doc/user/project/issues/img/confidential_mr_dropdown_v12_1.png +++ b/doc/user/project/issues/img/confidential_mr_dropdown_v12_1.png diff --git a/doc/user/project/issues/img/create_mr_from_issue.png b/doc/user/project/issues/img/create_mr_from_issue.png Binary files differindex 680c42b5df0..d05a678cd17 100644 --- a/doc/user/project/issues/img/create_mr_from_issue.png +++ b/doc/user/project/issues/img/create_mr_from_issue.png diff --git a/doc/user/project/issues/img/design_management_v12_2.png b/doc/user/project/issues/img/design_management_v12_2.png Binary files differindex 6da747a3f21..ad803df4e63 100644 --- a/doc/user/project/issues/img/design_management_v12_2.png +++ b/doc/user/project/issues/img/design_management_v12_2.png diff --git a/doc/user/project/issues/img/issues_main_view_numbered.png b/doc/user/project/issues/img/issues_main_view_numbered.png Binary files differindex 16cb6b497b0..92b9df44972 100644 --- a/doc/user/project/issues/img/issues_main_view_numbered.png +++ b/doc/user/project/issues/img/issues_main_view_numbered.png diff --git a/doc/user/project/issues/img/reopen-issue.png b/doc/user/project/issues/img/reopen-issue.png Binary files differindex 1749be31239..fc48742afe0 100644 --- a/doc/user/project/issues/img/reopen-issue.png +++ b/doc/user/project/issues/img/reopen-issue.png diff --git a/doc/user/project/issues/img/report-abuse.png b/doc/user/project/issues/img/report-abuse.png Binary files differindex f189cbf1d36..f8cef22da03 100644 --- a/doc/user/project/issues/img/report-abuse.png +++ b/doc/user/project/issues/img/report-abuse.png diff --git a/doc/user/project/issues/img/show-all-activity.png b/doc/user/project/issues/img/show-all-activity.png Binary files differindex c43ba75ce25..55c6f5ab5db 100644 --- a/doc/user/project/issues/img/show-all-activity.png +++ b/doc/user/project/issues/img/show-all-activity.png diff --git a/doc/user/project/labels.md b/doc/user/project/labels.md index a00c1c980d2..cc1274faa2c 100644 --- a/doc/user/project/labels.md +++ b/doc/user/project/labels.md @@ -93,8 +93,10 @@ GitLab will add the following default labels to the project: To create a **group label**, navigate to **Issues > Labels** in the **group** and create it from there. This page only shows group labels in this group. -Alternatively, you can create group labels from the Epic sidebar. Please note that the -created label will belong to the immediate group to which the epic belongs. **(ULTIMATE)** +Alternatively, you can create group labels from the Epic sidebar. **(ULTIMATE)** + +Please note that the created label will belong to the immediate group to which the +epic belongs. ![Create Labels from Epic](img/labels_epic_sidebar_v12_1.png) diff --git a/doc/user/project/merge_requests/img/allow_collaboration.png b/doc/user/project/merge_requests/img/allow_collaboration.png Binary files differindex e40e8a6b11c..cc13493646d 100644 --- a/doc/user/project/merge_requests/img/allow_collaboration.png +++ b/doc/user/project/merge_requests/img/allow_collaboration.png diff --git a/doc/user/project/merge_requests/img/allow_collaboration_after_save.png b/doc/user/project/merge_requests/img/allow_collaboration_after_save.png Binary files differindex 4ba4c84c8c5..bc7678b21ec 100644 --- a/doc/user/project/merge_requests/img/allow_collaboration_after_save.png +++ b/doc/user/project/merge_requests/img/allow_collaboration_after_save.png diff --git a/doc/user/project/merge_requests/img/approvals_premium_mr_widget.png b/doc/user/project/merge_requests/img/approvals_premium_mr_widget.png Binary files differindex b6dc86f312e..2598cc71c33 100644 --- a/doc/user/project/merge_requests/img/approvals_premium_mr_widget.png +++ b/doc/user/project/merge_requests/img/approvals_premium_mr_widget.png diff --git a/doc/user/project/merge_requests/img/approvals_premium_project_edit.png b/doc/user/project/merge_requests/img/approvals_premium_project_edit.png Binary files differindex b6f6188b9cd..6a09412533f 100644 --- a/doc/user/project/merge_requests/img/approvals_premium_project_edit.png +++ b/doc/user/project/merge_requests/img/approvals_premium_project_edit.png diff --git a/doc/user/project/merge_requests/img/approvals_starter_project_edit.png b/doc/user/project/merge_requests/img/approvals_starter_project_edit.png Binary files differindex 868b9d58740..4c554d846cc 100644 --- a/doc/user/project/merge_requests/img/approvals_starter_project_edit.png +++ b/doc/user/project/merge_requests/img/approvals_starter_project_edit.png diff --git a/doc/user/project/merge_requests/img/approvals_starter_project_empty.png b/doc/user/project/merge_requests/img/approvals_starter_project_empty.png Binary files differindex 7375820224c..fc88a59a745 100644 --- a/doc/user/project/merge_requests/img/approvals_starter_project_empty.png +++ b/doc/user/project/merge_requests/img/approvals_starter_project_empty.png diff --git a/doc/user/project/merge_requests/img/approve.png b/doc/user/project/merge_requests/img/approve.png Binary files differindex e68259ac5c2..e2641f48c7a 100644 --- a/doc/user/project/merge_requests/img/approve.png +++ b/doc/user/project/merge_requests/img/approve.png diff --git a/doc/user/project/merge_requests/img/approve_additionally.png b/doc/user/project/merge_requests/img/approve_additionally.png Binary files differindex 3db5a9159e5..bab0cd4e041 100644 --- a/doc/user/project/merge_requests/img/approve_additionally.png +++ b/doc/user/project/merge_requests/img/approve_additionally.png diff --git a/doc/user/project/merge_requests/img/create_from_email.png b/doc/user/project/merge_requests/img/create_from_email.png Binary files differindex 5cb2afaf976..14eef473e27 100644 --- a/doc/user/project/merge_requests/img/create_from_email.png +++ b/doc/user/project/merge_requests/img/create_from_email.png diff --git a/doc/user/project/merge_requests/img/edit_blocking_merge_requests.png b/doc/user/project/merge_requests/img/edit_blocking_merge_requests.png Binary files differindex 0fe26d602e3..98345f2f0d1 100644 --- a/doc/user/project/merge_requests/img/edit_blocking_merge_requests.png +++ b/doc/user/project/merge_requests/img/edit_blocking_merge_requests.png diff --git a/doc/user/project/merge_requests/img/edit_blocking_merge_requests_inaccessible.png b/doc/user/project/merge_requests/img/edit_blocking_merge_requests_inaccessible.png Binary files differindex a1003c41c22..b19cf1db94b 100644 --- a/doc/user/project/merge_requests/img/edit_blocking_merge_requests_inaccessible.png +++ b/doc/user/project/merge_requests/img/edit_blocking_merge_requests_inaccessible.png diff --git a/doc/user/project/merge_requests/img/filter_approver_merge_requests.png b/doc/user/project/merge_requests/img/filter_approver_merge_requests.png Binary files differindex 9c386391a4f..4c28ee17f47 100644 --- a/doc/user/project/merge_requests/img/filter_approver_merge_requests.png +++ b/doc/user/project/merge_requests/img/filter_approver_merge_requests.png diff --git a/doc/user/project/merge_requests/img/filter_wip_merge_requests.png b/doc/user/project/merge_requests/img/filter_wip_merge_requests.png Binary files differindex 8df6a3c9a29..0989b41e2a4 100644 --- a/doc/user/project/merge_requests/img/filter_wip_merge_requests.png +++ b/doc/user/project/merge_requests/img/filter_wip_merge_requests.png diff --git a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_settings.png b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_settings.png Binary files differindex ea3aff59aa1..ed374b11fbd 100644 --- a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_settings.png +++ b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_only_if_succeeds_settings.png diff --git a/doc/user/project/merge_requests/img/multiple_assignees_for_merge_requests_sidebar.png b/doc/user/project/merge_requests/img/multiple_assignees_for_merge_requests_sidebar.png Binary files differindex 9ae6e350798..dde2680ed74 100644 --- a/doc/user/project/merge_requests/img/multiple_assignees_for_merge_requests_sidebar.png +++ b/doc/user/project/merge_requests/img/multiple_assignees_for_merge_requests_sidebar.png diff --git a/doc/user/project/merge_requests/img/remove_approval.png b/doc/user/project/merge_requests/img/remove_approval.png Binary files differindex 6083e1745ef..b178d26cf85 100644 --- a/doc/user/project/merge_requests/img/remove_approval.png +++ b/doc/user/project/merge_requests/img/remove_approval.png diff --git a/doc/user/project/merge_requests/img/show_blocking_merge_requests_in_mr_widget.png b/doc/user/project/merge_requests/img/show_blocking_merge_requests_in_mr_widget.png Binary files differindex a1241f9e38c..3f4fcc5781d 100644 --- a/doc/user/project/merge_requests/img/show_blocking_merge_requests_in_mr_widget.png +++ b/doc/user/project/merge_requests/img/show_blocking_merge_requests_in_mr_widget.png diff --git a/doc/user/project/merge_requests/img/squash_mr_message.png b/doc/user/project/merge_requests/img/squash_mr_message.png Binary files differindex 8734cab29aa..8c7dc7886f7 100644 --- a/doc/user/project/merge_requests/img/squash_mr_message.png +++ b/doc/user/project/merge_requests/img/squash_mr_message.png diff --git a/doc/user/project/merge_requests/img/wip_blocked_accept_button.png b/doc/user/project/merge_requests/img/wip_blocked_accept_button.png Binary files differindex b6d38d85165..ab2c8425b83 100644 --- a/doc/user/project/merge_requests/img/wip_blocked_accept_button.png +++ b/doc/user/project/merge_requests/img/wip_blocked_accept_button.png diff --git a/doc/user/project/operations/img/error_tracking_list.png b/doc/user/project/operations/img/error_tracking_list.png Binary files differindex aa0f9867fdb..194c7b440a4 100644 --- a/doc/user/project/operations/img/error_tracking_list.png +++ b/doc/user/project/operations/img/error_tracking_list.png diff --git a/doc/user/project/operations/img/external_dashboard_link.png b/doc/user/project/operations/img/external_dashboard_link.png Binary files differindex 4fb8bce7cd0..82c5e05e467 100644 --- a/doc/user/project/operations/img/external_dashboard_link.png +++ b/doc/user/project/operations/img/external_dashboard_link.png diff --git a/doc/user/project/operations/img/external_dashboard_settings.png b/doc/user/project/operations/img/external_dashboard_settings.png Binary files differindex 8dc380f01e2..e1b7fa56a1c 100644 --- a/doc/user/project/operations/img/external_dashboard_settings.png +++ b/doc/user/project/operations/img/external_dashboard_settings.png diff --git a/doc/user/project/operations/img/feature_flags_list.png b/doc/user/project/operations/img/feature_flags_list.png Binary files differindex 5313a163fec..9a7af78d8a2 100644 --- a/doc/user/project/operations/img/feature_flags_list.png +++ b/doc/user/project/operations/img/feature_flags_list.png diff --git a/doc/user/project/operations/img/specs_list.png b/doc/user/project/operations/img/specs_list.png Binary files differindex 9630c907cfc..da17ef0e959 100644 --- a/doc/user/project/operations/img/specs_list.png +++ b/doc/user/project/operations/img/specs_list.png diff --git a/doc/user/project/packages/img/npm_package_view.png b/doc/user/project/packages/img/npm_package_view.png Binary files differindex 8baf7d0ef9f..e0634718c02 100644 --- a/doc/user/project/packages/img/npm_package_view.png +++ b/doc/user/project/packages/img/npm_package_view.png diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/img/get_domain_verification_code_v12_0.png b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/get_domain_verification_code_v12_0.png Binary files differindex b4dcdc9bb60..3b93572a8f1 100644 --- a/doc/user/project/pages/custom_domains_ssl_tls_certification/img/get_domain_verification_code_v12_0.png +++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/get_domain_verification_code_v12_0.png diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/img/lets_encrypt_integration_v12_1.png b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/lets_encrypt_integration_v12_1.png Binary files differindex 2e825e84d92..5eab04a61a9 100644 --- a/doc/user/project/pages/custom_domains_ssl_tls_certification/img/lets_encrypt_integration_v12_1.png +++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/lets_encrypt_integration_v12_1.png diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/img/retry_domain_verification_v12_0.png b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/retry_domain_verification_v12_0.png Binary files differindex db8f25bc6c3..5f2f100e883 100644 --- a/doc/user/project/pages/custom_domains_ssl_tls_certification/img/retry_domain_verification_v12_0.png +++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/img/retry_domain_verification_v12_0.png diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md index 2470e78819f..ee0550bfca2 100644 --- a/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md +++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md @@ -67,7 +67,7 @@ There are some certificate authorities that offer free certificates, aiming to make the internet more secure to everyone. The most popular is [Let's Encrypt](https://letsencrypt.org/), which issues certificates trusted by most of browsers, it's open -source, and free to use. See our tutorial on [how to secure your GitLab Pages website with Let's Encrypt](../lets_encrypt_for_gitlab_pages.md). +source, and free to use. See [GitLab Pages integration with Let's Encrypt](../custom_domains_ssl_tls_certification/lets_encrypt_integration.md) to enable HTTPS on your custom domain. Similarly popular are [certificates issued by CloudFlare](https://www.cloudflare.com/ssl/), which also offers a [free CDN service](https://blog.cloudflare.com/cloudflares-free-cdn-and-you/). diff --git a/doc/user/project/pages/img/pages_project_templates_v11_8.png b/doc/user/project/pages/img/pages_project_templates_v11_8.png Binary files differindex a645d28260b..61cae88b5a8 100644 --- a/doc/user/project/pages/img/pages_project_templates_v11_8.png +++ b/doc/user/project/pages/img/pages_project_templates_v11_8.png diff --git a/doc/user/project/pages/img/remove_pages.png b/doc/user/project/pages/img/remove_pages.png Binary files differindex 60f76f15f93..d6c37ef30cd 100644 --- a/doc/user/project/pages/img/remove_pages.png +++ b/doc/user/project/pages/img/remove_pages.png diff --git a/doc/user/project/pipelines/img/pipeline_schedule_variables.png b/doc/user/project/pipelines/img/pipeline_schedule_variables.png Binary files differindex 29846206491..ce3c3dc6af1 100644 --- a/doc/user/project/pipelines/img/pipeline_schedule_variables.png +++ b/doc/user/project/pipelines/img/pipeline_schedule_variables.png diff --git a/doc/user/project/pipelines/img/pipeline_schedules_new_form.png b/doc/user/project/pipelines/img/pipeline_schedules_new_form.png Binary files differindex e135dd51070..993fbf8ca00 100644 --- a/doc/user/project/pipelines/img/pipeline_schedules_new_form.png +++ b/doc/user/project/pipelines/img/pipeline_schedules_new_form.png diff --git a/doc/user/project/releases/img/releases.png b/doc/user/project/releases/img/releases.png Binary files differindex f8b1b7305ad..da5bcd9d913 100644 --- a/doc/user/project/releases/img/releases.png +++ b/doc/user/project/releases/img/releases.png diff --git a/doc/user/project/repository/img/download_source_code.png b/doc/user/project/repository/img/download_source_code.png Binary files differindex 17f2cb4b3e8..56808061980 100644 --- a/doc/user/project/repository/img/download_source_code.png +++ b/doc/user/project/repository/img/download_source_code.png diff --git a/doc/user/project/settings/img/general_settings.png b/doc/user/project/settings/img/general_settings.png Binary files differindex 4ff6fff5ca3..f88a158d2be 100644 --- a/doc/user/project/settings/img/general_settings.png +++ b/doc/user/project/settings/img/general_settings.png diff --git a/doc/user/project/settings/img/import_export_download_export.png b/doc/user/project/settings/img/import_export_download_export.png Binary files differindex ab81c87bf5f..c7ab7565fc7 100644 --- a/doc/user/project/settings/img/import_export_download_export.png +++ b/doc/user/project/settings/img/import_export_download_export.png diff --git a/doc/user/project/settings/img/import_export_export_button.png b/doc/user/project/settings/img/import_export_export_button.png Binary files differindex 9e368739695..6933e3edfcc 100644 --- a/doc/user/project/settings/img/import_export_export_button.png +++ b/doc/user/project/settings/img/import_export_export_button.png diff --git a/doc/user/project/settings/img/import_export_mail_link.png b/doc/user/project/settings/img/import_export_mail_link.png Binary files differindex 985c37650d3..1bd9a071178 100644 --- a/doc/user/project/settings/img/import_export_mail_link.png +++ b/doc/user/project/settings/img/import_export_mail_link.png diff --git a/doc/user/project/settings/img/import_export_new_project.png b/doc/user/project/settings/img/import_export_new_project.png Binary files differindex fc1f73c5d6e..0e2365ecb68 100644 --- a/doc/user/project/settings/img/import_export_new_project.png +++ b/doc/user/project/settings/img/import_export_new_project.png diff --git a/doc/user/project/settings/img/import_export_select_file.png b/doc/user/project/settings/img/import_export_select_file.png Binary files differindex e3e1a5ef980..90a3e8d5c4e 100644 --- a/doc/user/project/settings/img/import_export_select_file.png +++ b/doc/user/project/settings/img/import_export_select_file.png diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md index 35d5320c0b1..9c1a31fb7c3 100644 --- a/doc/user/project/settings/import_export.md +++ b/doc/user/project/settings/import_export.md @@ -66,6 +66,7 @@ The following items will be exported: - Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities - LFS objects +- Issue boards The following items will NOT be exported: diff --git a/doc/user/project/web_ide/img/terminal_status.png b/doc/user/project/web_ide/img/terminal_status.png Binary files differindex c37aa02b07a..91c341a9854 100644 --- a/doc/user/project/web_ide/img/terminal_status.png +++ b/doc/user/project/web_ide/img/terminal_status.png diff --git a/doc/workflow/img/notification_global_settings.png b/doc/workflow/img/notification_global_settings.png Binary files differindex 72f7418f1f8..699f726c442 100644 --- a/doc/workflow/img/notification_global_settings.png +++ b/doc/workflow/img/notification_global_settings.png diff --git a/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb b/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb index e6e0aaab60b..6ab4fca3854 100644 --- a/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb +++ b/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb @@ -8,31 +8,51 @@ module Gitlab def unmet? deployment_cluster.present? && deployment_cluster.managed? && - (kubernetes_namespace.new_record? || kubernetes_namespace.service_account_token.blank?) + missing_namespace? end def complete! return unless unmet? - create_or_update_namespace + create_namespace end private + def missing_namespace? + kubernetes_namespace.nil? || kubernetes_namespace.service_account_token.blank? + end + def deployment_cluster build.deployment&.cluster end + def environment + build.deployment.environment + end + def kubernetes_namespace strong_memoize(:kubernetes_namespace) do - deployment_cluster.find_or_initialize_kubernetes_namespace_for_project(build.project) + Clusters::KubernetesNamespaceFinder.new( + deployment_cluster, + project: environment.project, + environment_slug: environment.slug, + allow_blank_token: true + ).execute end end - def create_or_update_namespace + def create_namespace Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService.new( cluster: deployment_cluster, - kubernetes_namespace: kubernetes_namespace + kubernetes_namespace: kubernetes_namespace || build_namespace_record + ).execute + end + + def build_namespace_record + Clusters::BuildKubernetesNamespaceService.new( + deployment_cluster, + environment: environment ).execute end end diff --git a/lib/gitlab/ci/templates/Packer.gitlab-ci.yml b/lib/gitlab/ci/templates/Packer.gitlab-ci.yml index 83e179f37c3..0a3cf3dcf77 100644 --- a/lib/gitlab/ci/templates/Packer.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Packer.gitlab-ci.yml @@ -1,5 +1,5 @@ image: - name: hashicorp/packer:1.0.4 + name: hashicorp/packer:latest entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' diff --git a/lib/gitlab/content_security_policy/config_loader.rb b/lib/gitlab/content_security_policy/config_loader.rb new file mode 100644 index 00000000000..b2f3345d33a --- /dev/null +++ b/lib/gitlab/content_security_policy/config_loader.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Gitlab + module ContentSecurityPolicy + class ConfigLoader + DIRECTIVES = %w(base_uri child_src connect_src default_src font_src + form_action frame_ancestors frame_src img_src manifest_src + media_src object_src script_src style_src worker_src).freeze + + def self.default_settings_hash + { + 'enabled' => false, + 'report_only' => false, + 'directives' => DIRECTIVES.each_with_object({}) { |directive, hash| hash[directive] = nil } + } + end + + def initialize(csp_directives) + @csp_directives = HashWithIndifferentAccess.new(csp_directives) + end + + def load(policy) + DIRECTIVES.each do |directive| + arguments = arguments_for(directive) + + next unless arguments.present? + + policy.public_send(directive, *arguments) # rubocop:disable GitlabSecurity/PublicSend + end + end + + private + + def arguments_for(directive) + arguments = @csp_directives[directive.to_s] + + return unless arguments.present? && arguments.is_a?(String) + + arguments.strip.split(' ').map(&:strip) + end + end + end +end diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index 381f1dd4e55..1f49a26f0a2 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -6,15 +6,16 @@ module Gitlab TIMEOUT_FOREGROUND = 3.seconds MAXIMUM_TEXT_HIGHLIGHT_SIZE = 1.megabyte - def self.highlight(blob_name, blob_content, language: nil, plain: false) - new(blob_name, blob_content, language: language) + def self.highlight(blob_name, blob_content, since: nil, language: nil, plain: false) + new(blob_name, blob_content, since: since, language: language) .highlight(blob_content, continue: false, plain: plain) end attr_reader :blob_name - def initialize(blob_name, blob_content, language: nil) + def initialize(blob_name, blob_content, since: nil, language: nil) @formatter = Rouge::Formatters::HTMLGitlab + @since = since @language = language @blob_name = blob_name @blob_content = blob_content @@ -53,13 +54,13 @@ module Gitlab end def highlight_plain(text) - @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe + @formatter.format(Rouge::Lexers::PlainText.lex(text), since: @since).html_safe end def highlight_rich(text, continue: true) tag = lexer.tag tokens = lexer.lex(text, continue: continue) - Timeout.timeout(timeout_time) { @formatter.format(tokens, tag: tag).html_safe } + Timeout.timeout(timeout_time) { @formatter.format(tokens, tag: tag, since: @since).html_safe } rescue Timeout::Error => e Gitlab::Sentry.track_exception(e) highlight_plain(text) diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 01437c67fa9..f3888857bb6 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -80,6 +80,10 @@ project_tree: - :ci_cd_settings - :error_tracking_setting - :metrics_setting + - boards: + - lists: + - label: + - :priorities # Only include the following attributes for the models specified. included_attributes: @@ -216,6 +220,8 @@ methods: - :action project_badges: - :type + lists: + - :list_type # EE specific relationships and settings to include. All of this will be merged # into the previous structures if EE is used. diff --git a/lib/gitlab/kubernetes/default_namespace.rb b/lib/gitlab/kubernetes/default_namespace.rb new file mode 100644 index 00000000000..c95362b024b --- /dev/null +++ b/lib/gitlab/kubernetes/default_namespace.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + class DefaultNamespace + attr_reader :cluster, :project + + delegate :platform_kubernetes, to: :cluster + + ## + # Ideally we would just use an environment record here instead of + # passing a project and name/slug separately, but we need to be able + # to look up namespaces before the environment has been persisted. + def initialize(cluster, project:) + @cluster = cluster + @project = project + end + + def from_environment_name(name) + from_environment_slug(generate_slug(name)) + end + + def from_environment_slug(slug) + default_platform_namespace(slug) || default_project_namespace(slug) + end + + private + + def default_platform_namespace(slug) + return unless platform_kubernetes&.namespace.present? + + if cluster.managed? && cluster.namespace_per_environment? + "#{platform_kubernetes.namespace}-#{slug}" + else + platform_kubernetes.namespace + end + end + + def default_project_namespace(slug) + namespace_slug = "#{project.path}-#{project.id}".downcase + + if cluster.namespace_per_environment? + namespace_slug += "-#{slug}" + end + + Gitlab::NamespaceSanitizer.sanitize(namespace_slug) + end + + ## + # Environment slug can be predicted given an environment + # name, so even if the environment isn't persisted yet we + # still know what to look for. + def generate_slug(name) + Gitlab::Slug::Environment.new(name).generate + end + end + end +end diff --git a/lib/gitlab/prometheus/query_variables.rb b/lib/gitlab/prometheus/query_variables.rb index 9cc21129547..ba2d33ee1c1 100644 --- a/lib/gitlab/prometheus/query_variables.rb +++ b/lib/gitlab/prometheus/query_variables.rb @@ -4,12 +4,9 @@ module Gitlab module Prometheus module QueryVariables def self.call(environment) - deployment_platform = environment.deployment_platform - namespace = deployment_platform&.kubernetes_namespace_for(environment.project) || '' - { ci_environment_slug: environment.slug, - kube_namespace: namespace, + kube_namespace: environment.deployment_namespace || '', environment_filter: %{container_name!="POD",environment="#{environment.slug}"} } end diff --git a/lib/gitlab/prometheus_client.rb b/lib/gitlab/prometheus_client.rb index f13156f898e..9fefffefcde 100644 --- a/lib/gitlab/prometheus_client.rb +++ b/lib/gitlab/prometheus_client.rb @@ -3,6 +3,7 @@ module Gitlab # Helper methods to interact with Prometheus network services & resources class PrometheusClient + include Gitlab::Utils::StrongMemoize Error = Class.new(StandardError) QueryError = Class.new(Gitlab::PrometheusClient::Error) @@ -14,10 +15,17 @@ module Gitlab # Minimal value of the `step` parameter for `query_range` in seconds. QUERY_RANGE_MIN_STEP = 60 - attr_reader :rest_client, :headers + # Key translation between RestClient and Gitlab::HTTP (HTTParty) + RESTCLIENT_GITLAB_HTTP_KEYMAP = { + ssl_cert_store: :cert_store + }.freeze - def initialize(rest_client) - @rest_client = rest_client + attr_reader :api_url, :options + private :api_url, :options + + def initialize(api_url, options = {}) + @api_url = api_url.chomp('/') + @options = options end def ping @@ -27,14 +35,10 @@ module Gitlab def proxy(type, args) path = api_path(type) get(path, args) - rescue RestClient::ExceptionWithResponse => ex - if ex.response - ex.response - else - raise PrometheusClient::Error, "Network connection error" - end - rescue RestClient::Exception - raise PrometheusClient::Error, "Network connection error" + rescue Gitlab::HTTP::ResponseError => ex + raise PrometheusClient::Error, "Network connection error" unless ex.response && ex.response.try(:code) + + handle_response(ex.response) end def query(query, time: Time.now) @@ -78,50 +82,58 @@ module Gitlab private def api_path(type) - ['api', 'v1', type].join('/') + [api_url, 'api', 'v1', type].join('/') end def json_api_get(type, args = {}) path = api_path(type) response = get(path, args) handle_response(response) - rescue RestClient::ExceptionWithResponse => ex - if ex.response - handle_exception_response(ex.response) - else - raise PrometheusClient::Error, "Network connection error" + rescue Gitlab::HTTP::ResponseError => ex + raise PrometheusClient::Error, "Network connection error" unless ex.response && ex.response.try(:code) + + handle_response(ex.response) + end + + def gitlab_http_key(key) + RESTCLIENT_GITLAB_HTTP_KEYMAP[key] || key + end + + def mapped_options + options.keys.map { |k| [gitlab_http_key(k), options[k]] }.to_h + end + + def http_options + strong_memoize(:http_options) do + { follow_redirects: false }.merge(mapped_options) end - rescue RestClient::Exception - raise PrometheusClient::Error, "Network connection error" end def get(path, args) - rest_client[path].get(params: args) + Gitlab::HTTP.get(path, { query: args }.merge(http_options) ) rescue SocketError - raise PrometheusClient::Error, "Can't connect to #{rest_client.url}" + raise PrometheusClient::Error, "Can't connect to #{api_url}" rescue OpenSSL::SSL::SSLError - raise PrometheusClient::Error, "#{rest_client.url} contains invalid SSL data" + raise PrometheusClient::Error, "#{api_url} contains invalid SSL data" rescue Errno::ECONNREFUSED raise PrometheusClient::Error, 'Connection refused' end def handle_response(response) - json_data = parse_json(response.body) - if response.code == 200 && json_data['status'] == 'success' - json_data['data'] || {} - else - raise PrometheusClient::Error, "#{response.code} - #{response.body}" - end - end + response_code = response.try(:code) + response_body = response.try(:body) + + raise PrometheusClient::Error, "#{response_code} - #{response_body}" unless response_code + + json_data = parse_json(response_body) if [200, 400].include?(response_code) - def handle_exception_response(response) - if response.code == 200 && response['status'] == 'success' - response['data'] || {} - elsif response.code == 400 - json_data = parse_json(response.body) + case response_code + when 200 + json_data['data'] if response['status'] == 'success' + when 400 raise PrometheusClient::QueryError, json_data['error'] || 'Bad data received' else - raise PrometheusClient::Error, "#{response.code} - #{response.body}" + raise PrometheusClient::Error, "#{response_code} - #{response_body}" end end diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index e2a7d3ef5ba..0d4ac504428 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -8,8 +8,8 @@ module Rouge # Creates a new <tt>Rouge::Formatter::HTMLGitlab</tt> instance. # # [+tag+] The tag (language) of the lexer used to generate the formatted tokens - def initialize(tag: nil) - @line_number = 1 + def initialize(tag: nil, since: nil) + @line_number = since || 1 @tag = tag end diff --git a/lib/sentry/client.rb b/lib/sentry/client.rb index 4022e8ff946..07cca1c8d1e 100644 --- a/lib/sentry/client.rb +++ b/lib/sentry/client.rb @@ -67,7 +67,7 @@ module Sentry def handle_request_exceptions yield - rescue HTTParty::Error => e + rescue Gitlab::HTTP::Error => e Gitlab::Sentry.track_acceptable_exception(e) raise_error 'Error when connecting to Sentry' rescue Net::OpenTimeout diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 071ea86405b..fa78cd70381 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -900,6 +900,9 @@ msgstr "" msgid "After a successful password update, you will be redirected to the login page where you can log in with your new password." msgstr "" +msgid "Alerts" +msgstr "" + msgid "All" msgstr "" @@ -6889,6 +6892,9 @@ msgstr "" msgid "More" msgstr "" +msgid "More actions" +msgstr "" + msgid "More information" msgstr "" diff --git a/package.json b/package.json index 4ff99f29e24..c368cf7c8e4 100644 --- a/package.json +++ b/package.json @@ -176,14 +176,14 @@ "jest-util": "^24.0.0", "jsdoc": "^3.5.5", "jsdoc-vue": "^1.0.0", - "karma": "^3.0.0", - "karma-chrome-launcher": "^2.2.0", - "karma-coverage-istanbul-reporter": "^2.0.4", + "karma": "^4.2.0", + "karma-chrome-launcher": "^3.0.0", + "karma-coverage-istanbul-reporter": "^2.1.0", "karma-jasmine": "^1.1.2", "karma-junit-reporter": "^1.2.0", "karma-mocha-reporter": "^2.2.5", "karma-sourcemap-loader": "^0.3.7", - "karma-webpack": "^4.0.0-beta.0", + "karma-webpack": "^4.0.2", "md5": "^2.2.1", "node-sass": "^4.12.0", "nodemon": "^1.18.9", diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index 4e5610d69b7..b184eeb1701 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -182,7 +182,7 @@ module QA end def gcloud_num_nodes - ENV.fetch('GCLOUD_NUM_NODES', 3) + ENV.fetch('GCLOUD_NUM_NODES', 1) end def has_gcloud_credentials? diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb index 84027119491..7fb3578cd0a 100644 --- a/spec/controllers/metrics_controller_spec.rb +++ b/spec/controllers/metrics_controller_spec.rb @@ -5,12 +5,19 @@ require 'spec_helper' describe MetricsController do include StubENV - let(:metrics_multiproc_dir) { Dir.mktmpdir } + let(:metrics_multiproc_dir) { @metrics_multiproc_dir } let(:whitelisted_ip) { '127.0.0.1' } let(:whitelisted_ip_range) { '10.0.0.0/24' } let(:ip_in_whitelisted_range) { '10.0.0.1' } let(:not_whitelisted_ip) { '10.0.1.1' } + around do |example| + Dir.mktmpdir do |path| + @metrics_multiproc_dir = path + example.run + end + end + before do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') allow(Prometheus::Client.configuration).to receive(:multiprocess_files_dir).and_return(metrics_multiproc_dir) diff --git a/spec/controllers/projects/serverless/functions_controller_spec.rb b/spec/controllers/projects/serverless/functions_controller_spec.rb index 18c594acae0..9f1ef3a4be8 100644 --- a/spec/controllers/projects/serverless/functions_controller_spec.rb +++ b/spec/controllers/projects/serverless/functions_controller_spec.rb @@ -10,12 +10,16 @@ describe Projects::Serverless::FunctionsController do let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:service) { cluster.platform_kubernetes } let(:project) { cluster.project } + let(:environment) { create(:environment, project: project) } + let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) } + let(:knative_services_finder) { environment.knative_services_finder } let(:namespace) do create(:cluster_kubernetes_namespace, cluster: cluster, cluster_project: cluster.cluster_project, - project: cluster.cluster_project.project) + project: cluster.cluster_project.project, + environment: environment) end before do @@ -47,12 +51,11 @@ describe Projects::Serverless::FunctionsController do end context 'when cache is ready' do - let(:knative_services_finder) { project.clusters.first.knative_services_finder(project) } let(:knative_state) { true } before do - allow_any_instance_of(Clusters::Cluster) - .to receive(:knative_services_finder) + allow(Clusters::KnativeServicesFinder) + .to receive(:new) .and_return(knative_services_finder) synchronous_reactive_cache(knative_services_finder) stub_kubeclient_service_pods( @@ -107,12 +110,12 @@ describe Projects::Serverless::FunctionsController do context 'valid data', :use_clean_rails_memory_store_caching do before do stub_kubeclient_service_pods - stub_reactive_cache(cluster.knative_services_finder(project), + stub_reactive_cache(knative_services_finder, { services: kube_knative_services_body(namespace: namespace.namespace, name: cluster.project.name)["items"], pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"] }, - *cluster.knative_services_finder(project).cache_args) + *knative_services_finder.cache_args) end it 'has a valid function name' do @@ -140,12 +143,12 @@ describe Projects::Serverless::FunctionsController do describe 'GET #index with data', :use_clean_rails_memory_store_caching do before do stub_kubeclient_service_pods - stub_reactive_cache(cluster.knative_services_finder(project), + stub_reactive_cache(knative_services_finder, { services: kube_knative_services_body(namespace: namespace.namespace, name: cluster.project.name)["items"], pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"] }, - *cluster.knative_services_finder(project).cache_args) + *knative_services_finder.cache_args) end it 'has data' do diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb index b0d14b672f4..d294e6d055e 100644 --- a/spec/factories/clusters/clusters.rb +++ b/spec/factories/clusters/clusters.rb @@ -6,6 +6,7 @@ FactoryBot.define do name 'test-cluster' cluster_type :project_type managed true + namespace_per_environment true factory :cluster_for_group, traits: [:provided_by_gcp, :group] @@ -29,6 +30,10 @@ FactoryBot.define do end end + trait :namespace_per_environment_disabled do + namespace_per_environment false + end + trait :provided_by_user do provider_type :user platform_type :kubernetes diff --git a/spec/factories/clusters/kubernetes_namespaces.rb b/spec/factories/clusters/kubernetes_namespaces.rb index 042be7b4c4a..8d6ad1b9f79 100644 --- a/spec/factories/clusters/kubernetes_namespaces.rb +++ b/spec/factories/clusters/kubernetes_namespaces.rb @@ -5,12 +5,21 @@ FactoryBot.define do association :cluster, :project, :provided_by_gcp after(:build) do |kubernetes_namespace| - if kubernetes_namespace.cluster.project_type? - cluster_project = kubernetes_namespace.cluster.cluster_project + cluster = kubernetes_namespace.cluster + + if cluster.project_type? + cluster_project = cluster.cluster_project kubernetes_namespace.project = cluster_project.project kubernetes_namespace.cluster_project = cluster_project end + + kubernetes_namespace.namespace ||= + Gitlab::Kubernetes::DefaultNamespace.new( + cluster, + project: kubernetes_namespace.project + ).from_environment_slug(kubernetes_namespace.environment&.slug) + kubernetes_namespace.service_account_name ||= "#{kubernetes_namespace.namespace}-service-account" end trait :with_token do diff --git a/spec/features/projects/serverless/functions_spec.rb b/spec/features/projects/serverless/functions_spec.rb index 9865dbbfb3c..e82e5b81021 100644 --- a/spec/features/projects/serverless/functions_spec.rb +++ b/spec/features/projects/serverless/functions_spec.rb @@ -39,17 +39,19 @@ describe 'Functions', :js do let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:service) { cluster.platform_kubernetes } let(:project) { cluster.project } - let(:knative_services_finder) { project.clusters.first.knative_services_finder(project) } + let(:environment) { create(:environment, project: project) } + let!(:deployment) { create(:deployment, :success, cluster: cluster, environment: environment) } + let(:knative_services_finder) { environment.knative_services_finder } let(:namespace) do create(:cluster_kubernetes_namespace, cluster: cluster, - cluster_project: cluster.cluster_project, - project: cluster.cluster_project.project) + project: cluster.cluster_project.project, + environment: environment) end before do - allow_any_instance_of(Clusters::Cluster) - .to receive(:knative_services_finder) + allow(Clusters::KnativeServicesFinder) + .to receive(:new) .and_return(knative_services_finder) synchronous_reactive_cache(knative_services_finder) stub_kubeclient_knative_services(stub_get_services_options) diff --git a/spec/features/projects/services/user_activates_issue_tracker_spec.rb b/spec/features/projects/services/user_activates_issue_tracker_spec.rb index 5803500a4d2..5f3bb794b48 100644 --- a/spec/features/projects/services/user_activates_issue_tracker_spec.rb +++ b/spec/features/projects/services/user_activates_issue_tracker_spec.rb @@ -61,7 +61,7 @@ describe 'User activates issue tracker', :js do context 'when the connection test fails' do it 'activates the service' do - stub_request(:head, url).to_raise(HTTParty::Error) + stub_request(:head, url).to_raise(Gitlab::HTTP::Error) click_link(tracker) diff --git a/spec/features/projects/services/user_activates_youtrack_spec.rb b/spec/features/projects/services/user_activates_youtrack_spec.rb index 67f0aa214e2..8fdeddfdfb4 100644 --- a/spec/features/projects/services/user_activates_youtrack_spec.rb +++ b/spec/features/projects/services/user_activates_youtrack_spec.rb @@ -48,7 +48,7 @@ describe 'User activates issue tracker', :js do context 'when the connection test fails' do it 'activates the service' do - stub_request(:head, url).to_raise(HTTParty::Error) + stub_request(:head, url).to_raise(Gitlab::HTTP::Error) click_link(tracker) fill_form diff --git a/spec/finders/clusters/knative_services_finder_spec.rb b/spec/finders/clusters/knative_services_finder_spec.rb index b731c2bd6bf..159724b3c1f 100644 --- a/spec/finders/clusters/knative_services_finder_spec.rb +++ b/spec/finders/clusters/knative_services_finder_spec.rb @@ -7,15 +7,19 @@ describe Clusters::KnativeServicesFinder do include ReactiveCachingHelpers let(:cluster) { create(:cluster, :project, :provided_by_gcp) } - let(:service) { cluster.platform_kubernetes } + let(:service) { environment.deployment_platform } let(:project) { cluster.cluster_project.project } + let(:environment) { create(:environment, project: project) } + let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) } let(:namespace) do create(:cluster_kubernetes_namespace, cluster: cluster, - cluster_project: cluster.cluster_project, - project: project) + project: project, + environment: environment) end + let(:finder) { described_class.new(cluster, environment) } + before do stub_kubeclient_knative_services(namespace: namespace.namespace) stub_kubeclient_service_pods( @@ -35,7 +39,7 @@ describe Clusters::KnativeServicesFinder do context 'when using synchronous reactive cache' do before do - synchronous_reactive_cache(cluster.knative_services_finder(project)) + synchronous_reactive_cache(finder) end context 'when there are functions for cluster namespace' do @@ -60,21 +64,21 @@ describe Clusters::KnativeServicesFinder do end describe '#service_pod_details' do - subject { cluster.knative_services_finder(project).service_pod_details(project.name) } + subject { finder.service_pod_details(project.name) } it_behaves_like 'a cached data' end describe '#services' do - subject { cluster.knative_services_finder(project).services } + subject { finder.services } it_behaves_like 'a cached data' end describe '#knative_detected' do - subject { cluster.knative_services_finder(project).knative_detected } + subject { finder.knative_detected } before do - synchronous_reactive_cache(cluster.knative_services_finder(project)) + synchronous_reactive_cache(finder) end context 'when knative is installed' do @@ -85,7 +89,7 @@ describe Clusters::KnativeServicesFinder do it { is_expected.to be_truthy } it "discovers knative installation" do expect { subject } - .to change { cluster.kubeclient.knative_client.discovered } + .to change { finder.cluster.kubeclient.knative_client.discovered } .from(false) .to(true) end diff --git a/spec/finders/clusters/kubernetes_namespace_finder_spec.rb b/spec/finders/clusters/kubernetes_namespace_finder_spec.rb new file mode 100644 index 00000000000..8beba0b99a4 --- /dev/null +++ b/spec/finders/clusters/kubernetes_namespace_finder_spec.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Clusters::KubernetesNamespaceFinder do + let(:finder) do + described_class.new( + cluster, + project: project, + environment_slug: 'production', + allow_blank_token: allow_blank_token + ) + end + + def create_namespace(environment, with_token: true) + create(:cluster_kubernetes_namespace, + (with_token ? :with_token : :without_token), + cluster: cluster, + project: project, + environment: environment + ) + end + + describe '#execute' do + let(:production) { create(:environment, project: project, slug: 'production') } + let(:staging) { create(:environment, project: project, slug: 'staging') } + + let(:cluster) { create(:cluster, :group, :provided_by_user) } + let(:project) { create(:project) } + let(:allow_blank_token) { false } + + subject { finder.execute } + + before do + allow(cluster).to receive(:namespace_per_environment?).and_return(namespace_per_environment) + end + + context 'cluster supports separate namespaces per environment' do + let(:namespace_per_environment) { true } + + context 'no persisted namespace is present' do + it { is_expected.to be_nil } + end + + context 'a namespace with an environment is present' do + context 'environment matches' do + let!(:namespace_with_environment) { create_namespace(production) } + + it { is_expected.to eq namespace_with_environment } + + context 'project cluster' do + let(:cluster) { create(:cluster, :project, :provided_by_user, projects: [project]) } + + it { is_expected.to eq namespace_with_environment } + end + + context 'service account token is blank' do + let!(:namespace_with_environment) { create_namespace(production, with_token: false) } + + it { is_expected.to be_nil } + + context 'allow_blank_token is true' do + let(:allow_blank_token) { true } + + it { is_expected.to eq namespace_with_environment } + end + end + end + + context 'environment does not match' do + let!(:namespace_with_environment) { create_namespace(staging) } + + it { is_expected.to be_nil } + end + end + end + + context 'cluster does not support separate namespaces per environment' do + let(:namespace_per_environment) { false } + + context 'no persisted namespace is present' do + it { is_expected.to be_nil } + end + + context 'a legacy namespace with no environment is present' do + let!(:legacy_namespace) { create_namespace(nil) } + + it { is_expected.to eq legacy_namespace } + + context 'project cluster' do + let(:cluster) { create(:cluster, :project, :provided_by_user, projects: [project]) } + + it { is_expected.to eq legacy_namespace } + end + + context 'service account token is blank' do + let!(:legacy_namespace) { create_namespace(nil, with_token: false) } + + it { is_expected.to be_nil } + + context 'allow_blank_token is true' do + let(:allow_blank_token) { true } + + it { is_expected.to eq legacy_namespace } + end + end + end + end + end +end diff --git a/spec/finders/projects/serverless/functions_finder_spec.rb b/spec/finders/projects/serverless/functions_finder_spec.rb index 8aea45b457c..589e4000d46 100644 --- a/spec/finders/projects/serverless/functions_finder_spec.rb +++ b/spec/finders/projects/serverless/functions_finder_spec.rb @@ -11,12 +11,15 @@ describe Projects::Serverless::FunctionsFinder do let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:service) { cluster.platform_kubernetes } let(:project) { cluster.project } + let(:environment) { create(:environment, project: project) } + let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) } + let(:knative_services_finder) { environment.knative_services_finder } let(:namespace) do create(:cluster_kubernetes_namespace, cluster: cluster, - cluster_project: cluster.cluster_project, - project: cluster.cluster_project.project) + project: project, + environment: environment) end before do @@ -29,11 +32,9 @@ describe Projects::Serverless::FunctionsFinder do end context 'when reactive_caching has finished' do - let(:knative_services_finder) { project.clusters.first.knative_services_finder(project) } - before do - allow_any_instance_of(Clusters::Cluster) - .to receive(:knative_services_finder) + allow(Clusters::KnativeServicesFinder) + .to receive(:new) .and_return(knative_services_finder) synchronous_reactive_cache(knative_services_finder) end @@ -47,8 +48,6 @@ describe Projects::Serverless::FunctionsFinder do end context 'reactive_caching is finished and knative is installed' do - let(:knative_services_finder) { project.clusters.first.knative_services_finder(project) } - it 'returns true' do stub_kubeclient_knative_services(namespace: namespace.namespace) stub_kubeclient_service_pods(nil, namespace: namespace.namespace) @@ -74,24 +73,24 @@ describe Projects::Serverless::FunctionsFinder do it 'there are functions', :use_clean_rails_memory_store_caching do stub_kubeclient_service_pods - stub_reactive_cache(cluster.knative_services_finder(project), + stub_reactive_cache(knative_services_finder, { services: kube_knative_services_body(namespace: namespace.namespace, name: cluster.project.name)["items"], pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"] }, - *cluster.knative_services_finder(project).cache_args) + *knative_services_finder.cache_args) expect(finder.execute).not_to be_empty end it 'has a function', :use_clean_rails_memory_store_caching do stub_kubeclient_service_pods - stub_reactive_cache(cluster.knative_services_finder(project), + stub_reactive_cache(knative_services_finder, { services: kube_knative_services_body(namespace: namespace.namespace, name: cluster.project.name)["items"], pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"] }, - *cluster.knative_services_finder(project).cache_args) + *knative_services_finder.cache_args) result = finder.service(cluster.environment_scope, cluster.project.name) expect(result).not_to be_empty @@ -109,7 +108,7 @@ describe Projects::Serverless::FunctionsFinder do let(:finder) { described_class.new(project) } before do - allow(finder).to receive(:prometheus_adapter).and_return(prometheus_adapter) + allow(Prometheus::AdapterService).to receive(:new).and_return(double(prometheus_adapter: prometheus_adapter)) allow(prometheus_adapter).to receive(:query).and_return(prometheus_empty_body('matrix')) end diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js index e4d62b044ca..8b6f7802b15 100644 --- a/spec/frontend/test_setup.js +++ b/spec/frontend/test_setup.js @@ -75,3 +75,18 @@ global.MutationObserver = () => ({ disconnect: () => {}, observe: () => {}, }); + +Object.assign(global, { + requestIdleCallback(cb) { + const start = Date.now(); + return setTimeout(() => { + cb({ + didTimeout: false, + timeRemaining: () => Math.max(0, 50 - (Date.now() - start)), + }); + }); + }, + cancelIdleCallback(id) { + clearTimeout(id); + }, +}); diff --git a/spec/helpers/dashboard_helper_spec.rb b/spec/helpers/dashboard_helper_spec.rb index 49e23366355..059ae128d93 100644 --- a/spec/helpers/dashboard_helper_spec.rb +++ b/spec/helpers/dashboard_helper_spec.rb @@ -12,7 +12,7 @@ describe DashboardHelper do it 'has all the expected links by default' do menu_items = [:projects, :groups, :activity, :milestones, :snippets] - expect(helper.dashboard_nav_links).to contain_exactly(*menu_items) + expect(helper.dashboard_nav_links).to include(*menu_items) end it 'does not contain cross project elements when the user cannot read cross project' do diff --git a/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js b/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js index e6a969bd855..b2fe315f6c6 100644 --- a/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js @@ -224,7 +224,7 @@ describe('AjaxFormVariableList', () => { describe('maskableRegex', () => { it('takes in the regex provided by the data attribute', () => { - expect(container.dataset.maskableRegex).toBe('^[a-zA-Z0-9_+=/-]{8,}$'); + expect(container.dataset.maskableRegex).toBe('^[a-zA-Z0-9_+=/@:-]{8,}$'); expect(ajaxVariableList.maskableRegex).toBe(container.dataset.maskableRegex); }); }); diff --git a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js index 064113e879a..c8d6f789ed0 100644 --- a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js @@ -162,7 +162,7 @@ describe('VariableList', () => { }); it('has a regex provided via a data attribute', () => { - expect($wrapper.attr('data-maskable-regex')).toBe('^[a-zA-Z0-9_+=/-]{8,}$'); + expect($wrapper.attr('data-maskable-regex')).toBe('^[a-zA-Z0-9_+=/@:-]{8,}$'); }); it('allows values that are 8 characters long', done => { diff --git a/spec/javascripts/pipelines/pipelines_actions_spec.js b/spec/javascripts/pipelines/pipelines_actions_spec.js index a7dcd532f4f..953a42b9d15 100644 --- a/spec/javascripts/pipelines/pipelines_actions_spec.js +++ b/spec/javascripts/pipelines/pipelines_actions_spec.js @@ -1,5 +1,6 @@ import Vue from 'vue'; -import eventHub from '~/pipelines/event_hub'; +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; import PipelinesActions from '~/pipelines/components/pipelines_actions.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; import { TEST_HOST } from 'spec/test_constants'; @@ -7,9 +8,15 @@ import { TEST_HOST } from 'spec/test_constants'; describe('Pipelines Actions dropdown', () => { const Component = Vue.extend(PipelinesActions); let vm; + let mock; afterEach(() => { vm.$destroy(); + mock.restore(); + }); + + beforeEach(() => { + mock = new MockAdapter(axios); }); describe('manual actions', () => { @@ -40,6 +47,22 @@ describe('Pipelines Actions dropdown', () => { expect(dropdownItem).toBeDisabled(); }); + + describe('on click', () => { + it('makes a request and toggles the loading state', done => { + mock.onPost(actions.path).reply(200); + + vm.$el.querySelector('.dropdown-menu li button').click(); + + expect(vm.isLoading).toEqual(true); + + setTimeout(() => { + expect(vm.isLoading).toEqual(false); + + done(); + }); + }); + }); }); describe('scheduled jobs', () => { @@ -71,26 +94,27 @@ describe('Pipelines Actions dropdown', () => { .catch(done.fail); }); - it('emits postAction event after confirming', () => { - const emitSpy = jasmine.createSpy('emit'); - eventHub.$on('postAction', emitSpy); + it('makes post request after confirming', done => { + mock.onPost(scheduledJobAction.path).reply(200); spyOn(window, 'confirm').and.callFake(() => true); findDropdownItem(scheduledJobAction).click(); expect(window.confirm).toHaveBeenCalled(); - expect(emitSpy).toHaveBeenCalledWith(scheduledJobAction.path); + setTimeout(() => { + expect(mock.history.post.length).toBe(1); + done(); + }); }); - it('does not emit postAction event if confirmation is cancelled', () => { - const emitSpy = jasmine.createSpy('emit'); - eventHub.$on('postAction', emitSpy); + it('does not make post request if confirmation is cancelled', () => { + mock.onPost(scheduledJobAction.path).reply(200); spyOn(window, 'confirm').and.callFake(() => false); findDropdownItem(scheduledJobAction).click(); expect(window.confirm).toHaveBeenCalled(); - expect(emitSpy).not.toHaveBeenCalled(); + expect(mock.history.post.length).toBe(0); }); it('displays the remaining time in the dropdown', () => { diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb index 62b688d4d3e..280941ff601 100644 --- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb @@ -173,7 +173,7 @@ describe Gitlab::BitbucketImport::Importer do context 'when importing a pull request throws an exception' do before do allow(pull_request).to receive(:raw).and_return('hello world') - allow(subject.client).to receive(:pull_request_comments).and_raise(HTTParty::Error) + allow(subject.client).to receive(:pull_request_comments).and_raise(Gitlab::HTTP::Error) end it 'logs an error without the backtrace' do diff --git a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb index d88a2097ba2..775550f2acc 100644 --- a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb +++ b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do - let(:build) { create(:ci_build) } - describe '#unmet?' do + let(:build) { create(:ci_build) } + subject { described_class.new(build).unmet? } context 'build has no deployment' do @@ -18,7 +18,6 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do context 'build has a deployment' do let!(:deployment) { create(:deployment, deployable: build, cluster: cluster) } - let(:cluster) { nil } context 'and a cluster to deploy to' do let(:cluster) { create(:cluster, :group) } @@ -32,12 +31,17 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do end context 'and a namespace is already created for this project' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, cluster: cluster, project: build.project) } + let(:kubernetes_namespace) { instance_double(Clusters::KubernetesNamespace, service_account_token: 'token') } + + before do + allow(Clusters::KubernetesNamespaceFinder).to receive(:new) + .and_return(double(execute: kubernetes_namespace)) + end it { is_expected.to be_falsey } context 'and the service_account_token is blank' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :without_token, cluster: cluster, project: build.project) } + let(:kubernetes_namespace) { instance_double(Clusters::KubernetesNamespace, service_account_token: nil) } it { is_expected.to be_truthy } end @@ -45,34 +49,79 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do end context 'and no cluster to deploy to' do + let(:cluster) { nil } + it { is_expected.to be_falsey } end end end describe '#complete!' do - let!(:deployment) { create(:deployment, deployable: build, cluster: cluster) } - let(:service) { double(execute: true) } - let(:cluster) { nil } + let(:build) { create(:ci_build) } + let(:prerequisite) { described_class.new(build) } - subject { described_class.new(build).complete! } + subject { prerequisite.complete! } context 'completion is required' do let(:cluster) { create(:cluster, :group) } + let(:deployment) { create(:deployment, cluster: cluster) } + let(:service) { double(execute: true) } + let(:kubernetes_namespace) { double } + + before do + allow(prerequisite).to receive(:unmet?).and_return(true) + allow(build).to receive(:deployment).and_return(deployment) + end + + context 'kubernetes namespace does not exist' do + let(:namespace_builder) { double(execute: kubernetes_namespace)} - it 'creates a kubernetes namespace' do - expect(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService) - .to receive(:new) - .with(cluster: cluster, kubernetes_namespace: instance_of(Clusters::KubernetesNamespace)) - .and_return(service) + before do + allow(Clusters::KubernetesNamespaceFinder).to receive(:new) + .and_return(double(execute: nil)) + end - expect(service).to receive(:execute).once + it 'creates a namespace using a new record' do + expect(Clusters::BuildKubernetesNamespaceService) + .to receive(:new) + .with(cluster, environment: deployment.environment) + .and_return(namespace_builder) - subject + expect(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService) + .to receive(:new) + .with(cluster: cluster, kubernetes_namespace: kubernetes_namespace) + .and_return(service) + + expect(service).to receive(:execute).once + + subject + end + end + + context 'kubernetes namespace exists (but has no service_account_token)' do + before do + allow(Clusters::KubernetesNamespaceFinder).to receive(:new) + .and_return(double(execute: kubernetes_namespace)) + end + + it 'creates a namespace using the tokenless record' do + expect(Clusters::BuildKubernetesNamespaceService).not_to receive(:new) + + expect(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService) + .to receive(:new) + .with(cluster: cluster, kubernetes_namespace: kubernetes_namespace) + .and_return(service) + + subject + end end end context 'completion is not required' do + before do + allow(prerequisite).to receive(:unmet?).and_return(false) + end + it 'does not create a namespace' do expect(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:new) diff --git a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb new file mode 100644 index 00000000000..e7670c9d523 --- /dev/null +++ b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ContentSecurityPolicy::ConfigLoader do + let(:policy) { ActionDispatch::ContentSecurityPolicy.new } + let(:csp_config) do + { + enabled: true, + report_only: false, + directives: { + base_uri: 'http://example.com', + child_src: "'self' https://child.example.com", + default_src: "'self' https://other.example.com", + script_src: "'self' https://script.exammple.com ", + worker_src: "data: https://worker.example.com" + } + } + end + + context '.default_settings_hash' do + it 'returns empty defaults' do + settings = described_class.default_settings_hash + + expect(settings['enabled']).to be_falsey + expect(settings['report_only']).to be_falsey + + described_class::DIRECTIVES.each do |directive| + expect(settings['directives'].has_key?(directive)).to be_truthy + expect(settings['directives'][directive]).to be_nil + end + end + end + + context '#load' do + subject { described_class.new(csp_config[:directives]) } + + def expected_config(directive) + csp_config[:directives][directive].split(' ').map(&:strip) + end + + it 'sets the policy properly' do + subject.load(policy) + + expect(policy.directives['base-uri']).to eq([csp_config[:directives][:base_uri]]) + expect(policy.directives['default-src']).to eq(expected_config(:default_src)) + expect(policy.directives['child-src']).to eq(expected_config(:child_src)) + expect(policy.directives['worker-src']).to eq(expected_config(:worker_src)) + end + + it 'ignores malformed policy statements' do + csp_config[:directives][:base_uri] = 123 + + subject.load(policy) + + expect(policy.directives['base-uri']).to be_nil + end + end +end diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index 4676db6b8d8..a410e4eab45 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -62,6 +62,14 @@ describe Gitlab::Highlight do expect(lines[2].text).to eq(' """') end + context 'since param is present' do + it 'highlights with the LC starting from "since" param' do + lines = described_class.highlight(file_name, content, since: 2).lines + + expect(lines[0]).to include('LC2') + end + end + context 'diff highlighting' do let(:file_name) { 'test.diff' } let(:content) { "+aaa\n+bbb\n- ccc\n ddd\n"} diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 929b6222900..ada8c649ff6 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -469,3 +469,17 @@ incident_management_setting: merge_trains: - project - merge_request +boards: +- group +- lists +- destroyable_lists +- milestone +- board_labels +- board_assignee +- assignee +- labels +lists: +- user +- milestone +- board +- label diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 9e54ca28e58..6d70b147666 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -7147,5 +7147,65 @@ "link_url": "http://www.example.com", "image_url": "http://www.example.com" } + ], + "boards": [ + { + "id": 29, + "project_id": 49, + "created_at": "2019-06-06T14:01:06.204Z", + "updated_at": "2019-06-06T14:22:37.045Z", + "name": "TestBoardABC", + "milestone_id": null, + "group_id": null, + "weight": null, + "lists": [ + { + "id": 59, + "board_id": 29, + "label_id": null, + "list_type": "backlog", + "position": null, + "created_at": "2019-06-06T14:01:06.214Z", + "updated_at": "2019-06-06T14:01:06.214Z", + "user_id": null, + "milestone_id": null + }, + { + "id": 61, + "board_id": 29, + "label_id": 20, + "list_type": "label", + "position": 0, + "created_at": "2019-06-06T14:01:43.197Z", + "updated_at": "2019-06-06T14:01:43.197Z", + "user_id": null, + "milestone_id": null, + "label": { + "id": 20, + "title": "testlabel", + "color": "#0033CC", + "project_id": 49, + "created_at": "2019-06-06T14:01:19.698Z", + "updated_at": "2019-06-06T14:01:19.698Z", + "template": false, + "description": null, + "group_id": null, + "type": "ProjectLabel", + "priorities": [] + } + }, + { + "id": 60, + "board_id": 29, + "label_id": null, + "list_type": "closed", + "position": null, + "created_at": "2019-06-06T14:01:06.221Z", + "updated_at": "2019-06-06T14:01:06.221Z", + "user_id": null, + "milestone_id": null + } + ] + } ] } diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index b9f6595762b..baec24590b4 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -160,13 +160,21 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do end it 'has project labels' do - expect(ProjectLabel.count).to eq(2) + expect(ProjectLabel.count).to eq(3) end it 'has no group labels' do expect(GroupLabel.count).to eq(0) end + it 'has issue boards' do + expect(Project.find_by_path('project').boards.count).to eq(1) + end + + it 'has lists associated with the issue board' do + expect(Project.find_by_path('project').boards.find_by_name('TestBoardABC').lists.count).to eq(3) + end + it 'has a project feature' do expect(@project.project_feature).not_to be_nil 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 1ff2eb9210f..fefbed93316 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -272,6 +272,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver do expect(saved_project_json).not_to include("runners_token" => 'token') end end + + it 'has a board and a list' do + expect(saved_project_json['boards'].first['lists']).not_to be_empty + end end end @@ -327,6 +331,9 @@ describe Gitlab::ImportExport::ProjectTreeSaver do 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 diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 28b187c3676..f0545176a90 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -235,6 +235,12 @@ MergeRequest::Metrics: - latest_build_started_at - latest_build_finished_at - first_deployed_to_production_at +- first_comment_at +- first_commit_at +- last_commit_at +- diff_size +- modified_paths_size +- commits_count Ci::Pipeline: - id - project_id @@ -687,3 +693,22 @@ ProjectMetricsSetting: - external_dashboard_url - created_at - updated_at +Board: +- id +- project_id +- created_at +- updated_at +- group_id +- milestone_id +- weight +- name +List: +- id +- board_id +- label_id +- list_type +- position +- created_at +- updated_at +- milestone_id +- user_id diff --git a/spec/lib/gitlab/kubernetes/default_namespace_spec.rb b/spec/lib/gitlab/kubernetes/default_namespace_spec.rb new file mode 100644 index 00000000000..1fda547f35c --- /dev/null +++ b/spec/lib/gitlab/kubernetes/default_namespace_spec.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Kubernetes::DefaultNamespace do + let(:generator) { described_class.new(cluster, project: environment.project) } + + describe '#from_environment_name' do + let(:cluster) { create(:cluster) } + let(:environment) { create(:environment) } + + subject { generator.from_environment_name(environment.name) } + + it 'generates a slug and passes it to #from_environment_slug' do + expect(Gitlab::Slug::Environment).to receive(:new) + .with(environment.name) + .and_return(double(generate: environment.slug)) + + expect(generator).to receive(:from_environment_slug) + .with(environment.slug) + .and_return(:mock_namespace) + + expect(subject).to eq :mock_namespace + end + end + + describe '#from_environment_slug' do + let(:platform) { create(:cluster_platform_kubernetes, namespace: platform_namespace) } + let(:cluster) { create(:cluster, platform_kubernetes: platform) } + let(:project) { create(:project, path: "Path-With-Capitals") } + let(:environment) { create(:environment, project: project) } + + subject { generator.from_environment_slug(environment.slug) } + + context 'namespace per environment is enabled' do + context 'platform namespace is specified' do + let(:platform_namespace) { 'platform-namespace' } + + it { is_expected.to eq "#{platform_namespace}-#{environment.slug}" } + + context 'cluster is unmanaged' do + let(:cluster) { create(:cluster, :not_managed, platform_kubernetes: platform) } + + it { is_expected.to eq platform_namespace } + end + end + + context 'platform namespace is blank' do + let(:platform_namespace) { nil } + let(:mock_namespace) { 'mock-namespace' } + + it 'constructs a namespace from the project and environment' do + expect(Gitlab::NamespaceSanitizer).to receive(:sanitize) + .with("#{project.path}-#{project.id}-#{environment.slug}".downcase) + .and_return(mock_namespace) + + expect(subject).to eq mock_namespace + end + end + end + + context 'namespace per environment is disabled' do + let(:cluster) { create(:cluster, :namespace_per_environment_disabled, platform_kubernetes: platform) } + + context 'platform namespace is specified' do + let(:platform_namespace) { 'platform-namespace' } + + it { is_expected.to eq platform_namespace } + end + + context 'platform namespace is blank' do + let(:platform_namespace) { nil } + let(:mock_namespace) { 'mock-namespace' } + + it 'constructs a namespace from the project and environment' do + expect(Gitlab::NamespaceSanitizer).to receive(:sanitize) + .with("#{project.path}-#{project.id}".downcase) + .and_return(mock_namespace) + + expect(subject).to eq mock_namespace + end + end + end + end +end diff --git a/spec/lib/gitlab/prometheus/query_variables_spec.rb b/spec/lib/gitlab/prometheus/query_variables_spec.rb index 6dc99ef26ec..3f9b245a3fb 100644 --- a/spec/lib/gitlab/prometheus/query_variables_spec.rb +++ b/spec/lib/gitlab/prometheus/query_variables_spec.rb @@ -23,7 +23,7 @@ describe Gitlab::Prometheus::QueryVariables do context 'with deployment platform' do context 'with project cluster' do - let(:kube_namespace) { environment.deployment_platform.cluster.kubernetes_namespace_for(project) } + let(:kube_namespace) { environment.deployment_namespace } before do create(:cluster, :project, :provided_by_user, projects: [project]) @@ -38,8 +38,8 @@ describe Gitlab::Prometheus::QueryVariables do let(:project2) { create(:project) } let(:kube_namespace) { k8s_ns.namespace } - let!(:k8s_ns) { create(:cluster_kubernetes_namespace, cluster: cluster, project: project) } - let!(:k8s_ns2) { create(:cluster_kubernetes_namespace, cluster: cluster, project: project2) } + let!(:k8s_ns) { create(:cluster_kubernetes_namespace, cluster: cluster, project: project, environment: environment) } + let!(:k8s_ns2) { create(:cluster_kubernetes_namespace, cluster: cluster, project: project2, environment: environment) } before do group.projects << project diff --git a/spec/lib/gitlab/prometheus_client_spec.rb b/spec/lib/gitlab/prometheus_client_spec.rb index f15ae83a02c..0a4e8dbced5 100644 --- a/spec/lib/gitlab/prometheus_client_spec.rb +++ b/spec/lib/gitlab/prometheus_client_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::PrometheusClient do include PrometheusHelpers - subject { described_class.new(RestClient::Resource.new('https://prometheus.example.com')) } + subject { described_class.new('https://prometheus.example.com') } describe '#ping' do it 'issues a "query" request to the API endpoint' do @@ -79,8 +79,16 @@ describe Gitlab::PrometheusClient do expect(req_stub).to have_been_requested end - it 'raises a Gitlab::PrometheusClient::Error error when a RestClient::Exception is rescued' do - req_stub = stub_prometheus_request_with_exception(prometheus_url, RestClient::Exception) + it 'raises a Gitlab::PrometheusClient::Error error when a Gitlab::HTTP::ResponseError is rescued' do + req_stub = stub_prometheus_request_with_exception(prometheus_url, Gitlab::HTTP::ResponseError) + + expect { subject } + .to raise_error(Gitlab::PrometheusClient::Error, "Network connection error") + expect(req_stub).to have_been_requested + end + + it 'raises a Gitlab::PrometheusClient::Error error when a Gitlab::HTTP::ResponseError with a code is rescued' do + req_stub = stub_prometheus_request_with_exception(prometheus_url, Gitlab::HTTP::ResponseError.new(code: 400)) expect { subject } .to raise_error(Gitlab::PrometheusClient::Error, "Network connection error") @@ -89,13 +97,13 @@ describe Gitlab::PrometheusClient do end context 'ping' do - subject { described_class.new(RestClient::Resource.new(prometheus_url)).ping } + subject { described_class.new(prometheus_url).ping } it_behaves_like 'exceptions are raised' end context 'proxy' do - subject { described_class.new(RestClient::Resource.new(prometheus_url)).proxy('query', { query: '1' }) } + subject { described_class.new(prometheus_url).proxy('query', { query: '1' }) } it_behaves_like 'exceptions are raised' end @@ -310,15 +318,32 @@ describe Gitlab::PrometheusClient do end end - context 'when RestClient::Exception is raised' do + context 'when Gitlab::HTTP::ResponseError is raised' do before do - stub_prometheus_request_with_exception(query_url, RestClient::Exception) + stub_prometheus_request_with_exception(query_url, response_error) + end + + context "without response code" do + let(:response_error) { Gitlab::HTTP::ResponseError } + it 'raises PrometheusClient::Error' do + expect { subject.proxy('query', { query: prometheus_query }) }.to( + raise_error(Gitlab::PrometheusClient::Error, 'Network connection error') + ) + end end - it 'raises PrometheusClient::Error' do - expect { subject.proxy('query', { query: prometheus_query }) }.to( - raise_error(Gitlab::PrometheusClient::Error, 'Network connection error') - ) + context "with response code" do + let(:response_error) do + response = Net::HTTPResponse.new(1.1, 400, '{}sumpthin') + allow(response).to receive(:body) { '{}' } + Gitlab::HTTP::ResponseError.new(response) + end + + it 'raises Gitlab::PrometheusClient::QueryError' do + expect { subject.proxy('query', { query: prometheus_query }) }.to( + raise_error(Gitlab::PrometheusClient::QueryError, 'Bad data received') + ) + end end end end diff --git a/spec/lib/sentry/client_spec.rb b/spec/lib/sentry/client_spec.rb index cb14204b99a..ca2b17b44e0 100644 --- a/spec/lib/sentry/client_spec.rb +++ b/spec/lib/sentry/client_spec.rb @@ -63,7 +63,7 @@ describe Sentry::Client do shared_examples 'maps exceptions' do exceptions = { - HTTParty::Error => 'Error when connecting to Sentry', + Gitlab::HTTP::Error => 'Error when connecting to Sentry', Net::OpenTimeout => 'Connection to Sentry timed out', SocketError => 'Received SocketError when trying to connect to Sentry', OpenSSL::SSL::SSLError => 'Sentry returned invalid SSL data', diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb index d9f31c46f59..eb6ccba5584 100644 --- a/spec/models/clusters/applications/prometheus_spec.rb +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -86,16 +86,15 @@ describe Clusters::Applications::Prometheus do project: cluster.cluster_project.project) end - it 'creates proxy prometheus rest client' do - expect(subject.prometheus_client).to be_instance_of(RestClient::Resource) + it 'creates proxy prometheus_client' do + expect(subject.prometheus_client).to be_instance_of(Gitlab::PrometheusClient) end - it 'creates proper url' do - expect(subject.prometheus_client.url).to eq("#{kubernetes_url}/api/v1/namespaces/gitlab-managed-apps/services/prometheus-prometheus-server:80/proxy") - end - - it 'copies options and headers from kube client to proxy client' do - expect(subject.prometheus_client.options).to eq(kube_client.rest_client.options.merge(headers: kube_client.headers)) + it 'copies proxy_url, options and headers from kube client to prometheus_client' do + expect(Gitlab::PrometheusClient) + .to(receive(:new)) + .with(a_valid_url, kube_client.rest_client.options.merge(headers: kube_client.headers)) + subject.prometheus_client end context 'when cluster is not reachable' do diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 96212d0c864..9afbe6328ca 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -38,11 +38,6 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do it { is_expected.to respond_to :project } - it do - expect(subject.knative_services_finder(subject.project)) - .to be_instance_of(Clusters::KnativeServicesFinder) - end - describe '.enabled' do subject { described_class.enabled } @@ -534,60 +529,39 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do end end - describe '#find_or_initialize_kubernetes_namespace_for_project' do - let(:cluster) { create(:cluster, :project, :provided_by_gcp) } - let(:project) { cluster.projects.first } - - subject { cluster.find_or_initialize_kubernetes_namespace_for_project(project) } - - context 'kubernetes namespace exists' do - context 'with no service account token' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, project: project, cluster: cluster) } - - it { is_expected.to eq kubernetes_namespace } - end + describe '#kubernetes_namespace_for' do + let(:cluster) { create(:cluster, :group) } + let(:environment) { create(:environment) } - context 'with a service account token' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, project: project, cluster: cluster) } + subject { cluster.kubernetes_namespace_for(environment) } - it { is_expected.to eq kubernetes_namespace } - end - end - - context 'kubernetes namespace does not exist' do - it 'initializes a new namespace and sets default values' do - expect(subject).to be_new_record - expect(subject.project).to eq project - expect(subject.cluster).to eq cluster - expect(subject.namespace).to be_present - expect(subject.service_account_name).to be_present - end + before do + expect(Clusters::KubernetesNamespaceFinder).to receive(:new) + .with(cluster, project: environment.project, environment_slug: environment.slug) + .and_return(double(execute: persisted_namespace)) end - context 'a custom scope is provided' do - let(:scope) { cluster.kubernetes_namespaces.has_service_account_token } - - subject { cluster.find_or_initialize_kubernetes_namespace_for_project(project, scope: scope) } - - context 'kubernetes namespace exists' do - context 'with no service account token' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, project: project, cluster: cluster) } + context 'a persisted namespace exists' do + let(:persisted_namespace) { create(:cluster_kubernetes_namespace) } - it 'initializes a new namespace and sets default values' do - expect(subject).to be_new_record - expect(subject.project).to eq project - expect(subject.cluster).to eq cluster - expect(subject.namespace).to be_present - expect(subject.service_account_name).to be_present - end - end + it { is_expected.to eq persisted_namespace.namespace } + end - context 'with a service account token' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, project: project, cluster: cluster) } + context 'no persisted namespace exists' do + let(:persisted_namespace) { nil } + let(:namespace_generator) { double } + let(:default_namespace) { 'a-default-namespace' } - it { is_expected.to eq kubernetes_namespace } - end + before do + expect(Gitlab::Kubernetes::DefaultNamespace).to receive(:new) + .with(cluster, project: environment.project) + .and_return(namespace_generator) + expect(namespace_generator).to receive(:from_environment_slug) + .with(environment.slug) + .and_return(default_namespace) end + + it { is_expected.to eq default_namespace } end end diff --git a/spec/models/clusters/kubernetes_namespace_spec.rb b/spec/models/clusters/kubernetes_namespace_spec.rb index b5cba80b806..d4e3a0ac84d 100644 --- a/spec/models/clusters/kubernetes_namespace_spec.rb +++ b/spec/models/clusters/kubernetes_namespace_spec.rb @@ -24,70 +24,60 @@ RSpec.describe Clusters::KubernetesNamespace, type: :model do end end - describe 'namespace uniqueness validation' do - let(:cluster_project) { create(:cluster_project) } - let(:kubernetes_namespace) { build(:cluster_kubernetes_namespace, namespace: 'my-namespace') } + describe '.with_environment_slug' do + let(:cluster) { create(:cluster, :group) } + let(:environment) { create(:environment, slug: slug) } - subject { kubernetes_namespace } + let(:slug) { 'production' } - context 'when cluster is using the namespace' do - before do - create(:cluster_kubernetes_namespace, - cluster: kubernetes_namespace.cluster, - namespace: 'my-namespace') - end + subject { described_class.with_environment_slug(slug) } - it { is_expected.not_to be_valid } - end + context 'there is no associated environment' do + let!(:namespace) { create(:cluster_kubernetes_namespace, cluster: cluster, project: environment.project) } - context 'when cluster is not using the namespace' do - it { is_expected.to be_valid } + it { is_expected.to be_empty } end - end - describe '#set_defaults' do - let(:kubernetes_namespace) { build(:cluster_kubernetes_namespace) } - let(:cluster) { kubernetes_namespace.cluster } - let(:platform) { kubernetes_namespace.platform_kubernetes } - - subject { kubernetes_namespace.set_defaults } - - describe '#namespace' do - before do - platform.update_column(:namespace, namespace) + context 'there is an assicated environment' do + let!(:namespace) do + create( + :cluster_kubernetes_namespace, + cluster: cluster, + project: environment.project, + environment: environment + ) end - context 'when platform has a namespace assigned' do - let(:namespace) { 'platform-namespace' } - - it 'copies the namespace' do - subject - - expect(kubernetes_namespace.namespace).to eq('platform-namespace') - end + context 'with a matching slug' do + it { is_expected.to eq [namespace] } end - context 'when platform does not have namespace assigned' do - let(:project) { kubernetes_namespace.project } - let(:namespace) { nil } - let(:project_slug) { "#{project.path}-#{project.id}" } - - it 'fallbacks to project namespace' do - subject + context 'without a matching slug' do + let(:environment) { create(:environment, slug: 'staging') } - expect(kubernetes_namespace.namespace).to eq(project_slug) - end + it { is_expected.to be_empty } end end + end - describe '#service_account_name' do - let(:service_account_name) { "#{kubernetes_namespace.namespace}-service-account" } + describe 'namespace uniqueness validation' do + let(:kubernetes_namespace) { build(:cluster_kubernetes_namespace, namespace: 'my-namespace') } - it 'sets a service account name based on namespace' do - subject + subject { kubernetes_namespace } - expect(kubernetes_namespace.service_account_name).to eq(service_account_name) + context 'when cluster is using the namespace' do + before do + create(:cluster_kubernetes_namespace, + cluster: kubernetes_namespace.cluster, + environment: kubernetes_namespace.environment, + namespace: 'my-namespace') end + + it { is_expected.not_to be_valid } + end + + context 'when cluster is not using the namespace' do + it { is_expected.to be_valid } end end diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb index 5811016ea4d..0c4cf291d20 100644 --- a/spec/models/clusters/platforms/kubernetes_spec.rb +++ b/spec/models/clusters/platforms/kubernetes_spec.rb @@ -205,192 +205,77 @@ describe Clusters::Platforms::Kubernetes do it { is_expected.to be_truthy } end - describe '#kubernetes_namespace_for' do - let(:cluster) { create(:cluster, :project) } - let(:project) { cluster.project } - - let(:platform) do - create(:cluster_platform_kubernetes, - cluster: cluster, - namespace: namespace) - end - - subject { platform.kubernetes_namespace_for(project) } - - context 'with a namespace assigned' do - let(:namespace) { 'namespace-123' } - - it { is_expected.to eq(namespace) } - - context 'kubernetes namespace is present but has no service account token' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster) } - - it { is_expected.to eq(namespace) } - end - end - - context 'with no namespace assigned' do - let(:namespace) { nil } - - context 'when kubernetes namespace is present' do - let(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, cluster: cluster) } - - before do - kubernetes_namespace - end - - it { is_expected.to eq(kubernetes_namespace.namespace) } - - context 'kubernetes namespace has no service account token' do - before do - kubernetes_namespace.update!(namespace: 'old-namespace', service_account_token: nil) - end + describe '#predefined_variables' do + let(:project) { create(:project) } + let(:cluster) { create(:cluster, :group, platform_kubernetes: platform) } + let(:platform) { create(:cluster_platform_kubernetes) } + let(:persisted_namespace) { create(:cluster_kubernetes_namespace, project: project, cluster: cluster) } - it { is_expected.to eq("#{project.path}-#{project.id}") } - end - end + let(:environment_name) { 'env/production' } + let(:environment_slug) { Gitlab::Slug::Environment.new(environment_name).generate } - context 'when kubernetes namespace is not present' do - it { is_expected.to eq("#{project.path}-#{project.id}") } - end - end - end + subject { platform.predefined_variables(project: project, environment_name: environment_name) } - describe '#predefined_variables' do - let!(:cluster) { create(:cluster, :project, platform_kubernetes: kubernetes) } - let(:kubernetes) { create(:cluster_platform_kubernetes, api_url: api_url, ca_cert: ca_pem) } - let(:api_url) { 'https://kube.domain.com' } - let(:ca_pem) { File.read(Rails.root.join('spec/fixtures/clusters/sample_cert.pem')) } - - subject { kubernetes.predefined_variables(project: cluster.project) } - - shared_examples 'setting variables' do - it 'sets the variables' do - expect(subject).to include( - { key: 'KUBE_URL', value: api_url, public: true }, - { key: 'KUBE_CA_PEM', value: ca_pem, public: true }, - { key: 'KUBE_CA_PEM_FILE', value: ca_pem, public: true, file: true } - ) - end + before do + allow(Clusters::KubernetesNamespaceFinder).to receive(:new) + .with(cluster, project: project, environment_slug: environment_slug) + .and_return(double(execute: persisted_namespace)) end - context 'kubernetes namespace is created with no service account token' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster) } + it { is_expected.to include(key: 'KUBE_URL', value: platform.api_url, public: true) } - it_behaves_like 'setting variables' + context 'platform has a CA certificate' do + let(:ca_pem) { File.read(Rails.root.join('spec/fixtures/clusters/sample_cert.pem')) } + let(:platform) { create(:cluster_platform_kubernetes, ca_cert: ca_pem) } - it 'does not set KUBE_TOKEN' do - expect(subject).not_to include( - { key: 'KUBE_TOKEN', value: kubernetes.token, public: false, masked: true } - ) - end + it { is_expected.to include(key: 'KUBE_CA_PEM', value: ca_pem, public: true) } + it { is_expected.to include(key: 'KUBE_CA_PEM_FILE', value: ca_pem, public: true, file: true) } end - context 'kubernetes namespace is created with service account token' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, cluster: cluster) } - - it_behaves_like 'setting variables' + context 'kubernetes namespace exists' do + let(:variable) { Hash(key: :fake_key, value: 'fake_value') } + let(:namespace_variables) { Gitlab::Ci::Variables::Collection.new([variable]) } - it 'sets KUBE_TOKEN' do - expect(subject).to include( - { key: 'KUBE_TOKEN', value: kubernetes_namespace.service_account_token, public: false, masked: true } - ) + before do + expect(persisted_namespace).to receive(:predefined_variables).and_return(namespace_variables) end - context 'the cluster has been set to unmanaged after the namespace was created' do - before do - cluster.update!(managed: false) - end - - it_behaves_like 'setting variables' - - it 'sets KUBE_TOKEN from the platform' do - expect(subject).to include( - { key: 'KUBE_TOKEN', value: kubernetes.token, public: false, masked: true } - ) - end - - context 'the platform has a custom namespace set' do - before do - kubernetes.update!(namespace: 'custom-namespace') - end - - it 'sets KUBE_NAMESPACE from the platform' do - expect(subject).to include( - { key: 'KUBE_NAMESPACE', value: kubernetes.namespace, public: true, masked: false } - ) - end - end - - context 'there is no namespace specified on the platform' do - let(:project) { cluster.project } - - before do - kubernetes.update!(namespace: nil) - end - - it 'sets KUBE_NAMESPACE to a default for the project' do - expect(subject).to include( - { key: 'KUBE_NAMESPACE', value: "#{project.path}-#{project.id}", public: true, masked: false } - ) - end - end - end + it { is_expected.to include(variable) } end - context 'group level cluster' do - let!(:cluster) { create(:cluster, :group, platform_kubernetes: kubernetes) } - - let(:project) { create(:project, group: cluster.group) } - - subject { kubernetes.predefined_variables(project: project) } - - context 'no kubernetes namespace for the project' do - it_behaves_like 'setting variables' - - it 'does not return KUBE_TOKEN' do - expect(subject).not_to include( - { key: 'KUBE_TOKEN', value: kubernetes.token, public: false } - ) - end - - context 'the cluster is not managed' do - let!(:cluster) { create(:cluster, :group, :not_managed, platform_kubernetes: kubernetes) } + context 'kubernetes namespace does not exist' do + let(:persisted_namespace) { nil } + let(:namespace) { 'kubernetes-namespace' } + let(:kubeconfig) { 'kubeconfig' } - it_behaves_like 'setting variables' - - it 'sets KUBE_TOKEN' do - expect(subject).to include( - { key: 'KUBE_TOKEN', value: kubernetes.token, public: false, masked: true } - ) - end - end + before do + allow(Gitlab::Kubernetes::DefaultNamespace).to receive(:new) + .with(cluster, project: project).and_return(double(from_environment_name: namespace)) + allow(platform).to receive(:kubeconfig).with(namespace).and_return(kubeconfig) end - context 'kubernetes namespace exists for the project' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, cluster: cluster, project: project) } + it { is_expected.not_to include(key: 'KUBE_TOKEN', value: platform.token, public: false, masked: true) } + it { is_expected.not_to include(key: 'KUBE_NAMESPACE', value: namespace) } + it { is_expected.not_to include(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) } - it_behaves_like 'setting variables' + context 'cluster is unmanaged' do + let(:cluster) { create(:cluster, :group, :not_managed, platform_kubernetes: platform) } - it 'sets KUBE_TOKEN' do - expect(subject).to include( - { key: 'KUBE_TOKEN', value: kubernetes_namespace.service_account_token, public: false, masked: true } - ) - end + it { is_expected.to include(key: 'KUBE_TOKEN', value: platform.token, public: false, masked: true) } + it { is_expected.to include(key: 'KUBE_NAMESPACE', value: namespace) } + it { is_expected.to include(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) } end end - context 'with a domain' do - let!(:cluster) do - create(:cluster, :provided_by_gcp, :with_domain, - platform_kubernetes: kubernetes) - end + context 'cluster variables' do + let(:variable) { Hash(key: :fake_key, value: 'fake_value') } + let(:cluster_variables) { Gitlab::Ci::Variables::Collection.new([variable]) } - it 'sets KUBE_INGRESS_BASE_DOMAIN' do - expect(subject).to include( - { key: 'KUBE_INGRESS_BASE_DOMAIN', value: cluster.domain, public: true } - ) + before do + expect(cluster).to receive(:predefined_variables).and_return(cluster_variables) end + + it { is_expected.to include(variable) } end end @@ -410,7 +295,7 @@ describe Clusters::Platforms::Kubernetes do end context 'with valid pods' do - let(:pod) { kube_pod(environment_slug: environment.slug, namespace: cluster.kubernetes_namespace_for(project), project_slug: project.full_path_slug) } + let(:pod) { kube_pod(environment_slug: environment.slug, namespace: cluster.kubernetes_namespace_for(environment), project_slug: project.full_path_slug) } let(:pod_with_no_terminal) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: "Pending") } let(:terminals) { kube_terminals(service, pod) } let(:pods) { [pod, pod, pod_with_no_terminal, kube_pod(environment_slug: "should-be-filtered-out")] } diff --git a/spec/models/concerns/prometheus_adapter_spec.rb b/spec/models/concerns/prometheus_adapter_spec.rb index 25a2d290f76..3d26ba95192 100644 --- a/spec/models/concerns/prometheus_adapter_spec.rb +++ b/spec/models/concerns/prometheus_adapter_spec.rb @@ -40,13 +40,13 @@ describe PrometheusAdapter, :use_clean_rails_memory_store_caching do describe 'matched_metrics' do let(:matched_metrics_query) { Gitlab::Prometheus::Queries::MatchedMetricQuery } - let(:prometheus_client_wrapper) { double(:prometheus_client_wrapper, label_values: nil) } + let(:prometheus_client) { double(:prometheus_client, label_values: nil) } context 'with valid data' do subject { service.query(:matched_metrics) } before do - allow(service).to receive(:prometheus_client_wrapper).and_return(prometheus_client_wrapper) + allow(service).to receive(:prometheus_client).and_return(prometheus_client) synchronous_reactive_cache(service) end diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index d2e0bed721e..521c4704c87 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -575,6 +575,34 @@ describe Environment, :use_clean_rails_memory_store_caching do end end + describe '#deployment_namespace' do + let(:environment) { create(:environment) } + + subject { environment.deployment_namespace } + + before do + allow(environment).to receive(:deployment_platform).and_return(deployment_platform) + end + + context 'no deployment platform available' do + let(:deployment_platform) { nil } + + it { is_expected.to be_nil } + end + + context 'deployment platform is available' do + let(:cluster) { create(:cluster, :provided_by_user, :project, projects: [environment.project]) } + let(:deployment_platform) { cluster.platform } + + it 'retrieves a namespace from the cluster' do + expect(cluster).to receive(:kubernetes_namespace_for) + .with(environment).and_return('mock-namespace') + + expect(subject).to eq 'mock-namespace' + end + end + end + describe '#terminals' do subject { environment.terminals } @@ -823,4 +851,35 @@ describe Environment, :use_clean_rails_memory_store_caching do subject.prometheus_adapter end end + + describe '#knative_services_finder' do + let(:environment) { create(:environment) } + + subject { environment.knative_services_finder } + + context 'environment has no deployments' do + it { is_expected.to be_nil } + end + + context 'environment has a deployment' do + let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) } + + context 'with no cluster associated' do + let(:cluster) { nil } + + it { is_expected.to be_nil } + end + + context 'with a cluster associated' do + let(:cluster) { create(:cluster) } + + it 'calls the service finder' do + expect(Clusters::KnativeServicesFinder).to receive(:new) + .with(cluster, environment).and_return(:finder) + + is_expected.to eq :finder + end + end + end + end end diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index a53add67066..e7dd7287a75 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -484,4 +484,12 @@ describe MergeRequestDiff do end end end + + describe '#lines_count' do + subject { diff_with_commits } + + it 'returns sum of all changed lines count in diff files' do + expect(subject.lines_count).to eq 109 + end + end end diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb index e9c7c94ad70..e5ac6ca65d6 100644 --- a/spec/models/project_services/prometheus_service_spec.rb +++ b/spec/models/project_services/prometheus_service_spec.rb @@ -105,10 +105,6 @@ describe PrometheusService, :use_clean_rails_memory_store_caching do context 'manual configuration is enabled' do let(:manual_configuration) { true } - it 'returns rest client from api_url' do - expect(service.prometheus_client.url).to eq(api_url) - end - it 'calls valid?' do allow(service).to receive(:valid?).and_call_original diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 157103123ad..dde766c3813 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1156,7 +1156,6 @@ describe Project do describe '#pipeline_for' do let(:project) { create(:project, :repository) } - let!(:pipeline) { create_pipeline(project) } shared_examples 'giving the correct pipeline' do it { is_expected.to eq(pipeline) } @@ -1168,24 +1167,34 @@ describe Project do end end - context 'with explicit sha' do - subject { project.pipeline_for('master', pipeline.sha) } + context 'with a matching pipeline' do + let!(:pipeline) { create_pipeline(project) } + + context 'with explicit sha' do + subject { project.pipeline_for('master', pipeline.sha) } + + it_behaves_like 'giving the correct pipeline' - it_behaves_like 'giving the correct pipeline' + context 'with supplied id' do + let!(:other_pipeline) { create_pipeline(project) } - context 'with supplied id' do - let!(:other_pipeline) { create_pipeline(project) } + subject { project.pipeline_for('master', pipeline.sha, other_pipeline.id) } + + it { is_expected.to eq(other_pipeline) } + end + end - subject { project.pipeline_for('master', pipeline.sha, other_pipeline.id) } + context 'with implicit sha' do + subject { project.pipeline_for('master') } - it { is_expected.to eq(other_pipeline) } + it_behaves_like 'giving the correct pipeline' end end - context 'with implicit sha' do + context 'when there is no matching pipeline' do subject { project.pipeline_for('master') } - it_behaves_like 'giving the correct pipeline' + it { is_expected.to be_nil } end end @@ -1194,11 +1203,9 @@ describe Project do let!(:pipeline) { create_pipeline(project) } let!(:other_pipeline) { create_pipeline(project) } - context 'with implicit sha' do - subject { project.pipelines_for('master') } + subject { project.pipelines_for(project.default_branch, project.commit.sha) } - it { is_expected.to contain_exactly(pipeline, other_pipeline) } - end + it { is_expected.to contain_exactly(pipeline, other_pipeline) } end describe '#builds_enabled' do @@ -2587,45 +2594,33 @@ describe Project do end describe '#deployment_variables' do - context 'when project has no deployment service' do - let(:project) { create(:project) } + let(:project) { create(:project) } + let(:environment) { 'production' } - it 'returns an empty array' do - expect(project.deployment_variables).to eq [] - end + subject { project.deployment_variables(environment: environment) } + + before do + expect(project).to receive(:deployment_platform).with(environment: environment) + .and_return(deployment_platform) end - context 'when project uses mock deployment service' do - let(:project) { create(:mock_deployment_project) } + context 'when project has no deployment platform' do + let(:deployment_platform) { nil } - it 'returns an empty array' do - expect(project.deployment_variables).to eq [] - end + it { is_expected.to eq [] } end - context 'when project has a deployment service' do - context 'when user configured kubernetes from CI/CD > Clusters and KubernetesNamespace migration has not been executed' do - let!(:cluster) { create(:cluster, :project, :provided_by_gcp) } - let(:project) { cluster.project } + context 'when project has a deployment platform' do + let(:platform_variables) { %w(platform variables) } + let(:deployment_platform) { double } - it 'does not return variables from this service' do - expect(project.deployment_variables).not_to include( - { key: 'KUBE_TOKEN', value: project.deployment_platform.token, public: false, masked: true } - ) - end + before do + expect(deployment_platform).to receive(:predefined_variables) + .with(project: project, environment_name: environment) + .and_return(platform_variables) end - context 'when user configured kubernetes from CI/CD > Clusters and KubernetesNamespace migration has been executed' do - let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token) } - let!(:cluster) { kubernetes_namespace.cluster } - let(:project) { kubernetes_namespace.project } - - it 'returns token from kubernetes namespace' do - expect(project.deployment_variables).to include( - { key: 'KUBE_TOKEN', value: kubernetes_namespace.service_account_token, public: false, masked: true } - ) - end - end + it { is_expected.to eq platform_variables } end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 35c335c5b5c..46b86e8393d 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -794,6 +794,24 @@ describe User do end end + describe '#accessible_deploy_keys' do + let(:user) { create(:user) } + let(:project) { create(:project) } + let!(:private_deploy_keys_project) { create(:deploy_keys_project) } + let!(:public_deploy_keys_project) { create(:deploy_keys_project) } + let!(:accessible_deploy_keys_project) { create(:deploy_keys_project, project: project) } + + before do + public_deploy_keys_project.deploy_key.update(public: true) + project.add_developer(user) + end + + it 'user can only see deploy keys accessible to right projects' do + expect(user.accessible_deploy_keys).to match_array([public_deploy_keys_project.deploy_key, + accessible_deploy_keys_project.deploy_key]) + end + end + describe '#deploy_keys' do include_context 'user keys' diff --git a/spec/presenters/blob_presenter_spec.rb b/spec/presenters/blob_presenter_spec.rb index eacf383be7d..95db2ba6a0d 100644 --- a/spec/presenters/blob_presenter_spec.rb +++ b/spec/presenters/blob_presenter_spec.rb @@ -28,24 +28,70 @@ describe BlobPresenter, :seed_helper do subject { described_class.new(blob) } it 'returns highlighted content' do - expect(Gitlab::Highlight).to receive(:highlight).with('files/ruby/regex.rb', git_blob.data, plain: nil, language: nil) + expect(Gitlab::Highlight) + .to receive(:highlight) + .with( + 'files/ruby/regex.rb', + git_blob.data, + since: nil, + plain: nil, + language: nil + ) subject.highlight end it 'returns plain content when :plain is true' do - expect(Gitlab::Highlight).to receive(:highlight).with('files/ruby/regex.rb', git_blob.data, plain: true, language: nil) + expect(Gitlab::Highlight) + .to receive(:highlight) + .with( + 'files/ruby/regex.rb', + git_blob.data, + since: nil, + plain: true, + language: nil + ) subject.highlight(plain: true) end + context '"since" and "to" are present' do + before do + allow(git_blob) + .to receive(:data) + .and_return("line one\nline two\nline 3\nline 4") + end + + it 'returns limited highlighted content' do + expect(Gitlab::Highlight) + .to receive(:highlight) + .with( + 'files/ruby/regex.rb', + "line two\nline 3\n", + since: 2, + language: nil, + plain: nil + ) + + subject.highlight(since: 2, to: 3) + end + end + context 'gitlab-language contains a match' do before do allow(blob).to receive(:language_from_gitattributes).and_return('ruby') end it 'passes language to inner call' do - expect(Gitlab::Highlight).to receive(:highlight).with('files/ruby/regex.rb', git_blob.data, plain: nil, language: 'ruby') + expect(Gitlab::Highlight) + .to receive(:highlight) + .with( + 'files/ruby/regex.rb', + git_blob.data, + since: nil, + plain: nil, + language: 'ruby' + ) subject.highlight end diff --git a/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb b/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb index 001545bb5df..b4bf39f3cdb 100644 --- a/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb +++ b/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb @@ -29,10 +29,6 @@ describe Projects::Settings::DeployKeysPresenter do it 'returns the enabled_keys size' do expect(presenter.enabled_keys_size).to eq(1) end - - it 'returns true if there is any enabled_keys' do - expect(presenter.any_keys_enabled?).to eq(true) - end end describe '#available_keys/#available_project_keys' do @@ -54,9 +50,5 @@ describe Projects::Settings::DeployKeysPresenter do it 'returns the available_project_keys size' do expect(presenter.available_project_keys_size).to eq(1) end - - it 'shows if there is an available key' do - expect(presenter.key_available?(deploy_key)).to eq(false) - end end end diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb index e8ed016db69..a7b919de2ef 100644 --- a/spec/requests/api/project_clusters_spec.rb +++ b/spec/requests/api/project_clusters_spec.rb @@ -336,7 +336,6 @@ describe API::ProjectClusters do it 'does not update cluster attributes' do expect(cluster.domain).not_to eq('new_domain.com') expect(cluster.platform_kubernetes.namespace).not_to eq('invalid_namespace') - expect(cluster.kubernetes_namespace_for(project)).not_to eq('invalid_namespace') end it 'returns validation errors' do diff --git a/spec/services/clusters/build_kubernetes_namespace_service_spec.rb b/spec/services/clusters/build_kubernetes_namespace_service_spec.rb new file mode 100644 index 00000000000..36c05469542 --- /dev/null +++ b/spec/services/clusters/build_kubernetes_namespace_service_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Clusters::BuildKubernetesNamespaceService do + let(:cluster) { create(:cluster, :project, :provided_by_gcp) } + let(:environment) { create(:environment) } + let(:project) { environment.project } + + let(:namespace_generator) { double(from_environment_slug: namespace) } + let(:namespace) { 'namespace' } + + subject { described_class.new(cluster, environment: environment).execute } + + before do + allow(Gitlab::Kubernetes::DefaultNamespace).to receive(:new).and_return(namespace_generator) + end + + shared_examples 'shared attributes' do + it 'initializes a new namespace and sets default values' do + expect(subject).to be_new_record + expect(subject.cluster).to eq cluster + expect(subject.project).to eq project + expect(subject.namespace).to eq namespace + expect(subject.service_account_name).to eq "#{namespace}-service-account" + end + end + + include_examples 'shared attributes' + + it 'sets cluster_project and environment' do + expect(subject.cluster_project).to eq cluster.cluster_project + expect(subject.environment).to eq environment + end + + context 'namespace per environment is disabled' do + let(:cluster) { create(:cluster, :project, :provided_by_gcp, :namespace_per_environment_disabled) } + + include_examples 'shared attributes' + + it 'does not set environment' do + expect(subject.cluster_project).to eq cluster.cluster_project + expect(subject.environment).to be_nil + end + end + + context 'group cluster' do + let(:cluster) { create(:cluster, :group, :provided_by_gcp) } + + include_examples 'shared attributes' + + it 'does not set cluster_project' do + expect(subject.cluster_project).to be_nil + expect(subject.environment).to eq environment + end + end +end diff --git a/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb b/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb index 44407ae2793..e44cc3f5a78 100644 --- a/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb +++ b/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb @@ -9,8 +9,9 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d let(:platform) { cluster.platform } let(:api_url) { 'https://kubernetes.example.com' } let(:project) { cluster.project } + let(:environment) { create(:environment, project: project) } let(:cluster_project) { cluster.cluster_project } - let(:namespace) { "#{project.path}-#{project.id}" } + let(:namespace) { "#{project.name}-#{project.id}-#{environment.slug}" } subject do described_class.new( @@ -79,7 +80,8 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d let(:kubernetes_namespace) do build(:cluster_kubernetes_namespace, cluster: cluster, - project: project) + project: project, + environment: environment) end it_behaves_like 'successful creation of kubernetes namespace' @@ -92,20 +94,22 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d build(:cluster_kubernetes_namespace, cluster: cluster, project: cluster_project.project, - cluster_project: cluster_project) + cluster_project: cluster_project, + environment: environment) end it_behaves_like 'successful creation of kubernetes namespace' end context 'when there is a Kubernetes Namespace associated' do - let(:namespace) { 'new-namespace' } + let(:namespace) { "new-namespace-#{environment.slug}" } let(:kubernetes_namespace) do create(:cluster_kubernetes_namespace, cluster: cluster, project: cluster_project.project, - cluster_project: cluster_project) + cluster_project: cluster_project, + environment: environment) end before do diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index e436af77ed4..9a6f64b825a 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -241,6 +241,18 @@ describe Projects::DestroyService do expect(destroy_project(project, user)).to be false end end + + context 'when registry is disabled' do + before do + stub_container_registry_config(enabled: false) + end + + it 'does not attempting to remove any tags' do + expect(Projects::ContainerRepository::DestroyService).not_to receive(:new) + + destroy_project(project, user) + end + end end context 'when there are tags for legacy root repository' do diff --git a/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb index 80debcd3a7a..dabfd61d3f5 100644 --- a/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb +++ b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb @@ -33,7 +33,7 @@ describe Projects::LfsPointers::LfsDownloadLinkListService do before do allow(project).to receive(:lfs_enabled?).and_return(true) - response = instance_double(HTTParty::Response) + response = instance_double(Gitlab::HTTP::Response) allow(response).to receive(:body).and_return(objects_response.to_json) allow(response).to receive(:success?).and_return(true) allow(Gitlab::HTTP).to receive(:post).and_return(response) @@ -95,7 +95,7 @@ describe Projects::LfsPointers::LfsDownloadLinkListService do shared_examples 'JSON parse errors' do |body| it 'raises error' do - response = instance_double(HTTParty::Response) + response = instance_double(Gitlab::HTTP::Response) allow(response).to receive(:body).and_return(body) allow(response).to receive(:success?).and_return(true) allow(Gitlab::HTTP).to receive(:post).and_return(response) diff --git a/spec/services/prometheus/proxy_service_spec.rb b/spec/services/prometheus/proxy_service_spec.rb index 4bdb20de4c9..03bda94e9c6 100644 --- a/spec/services/prometheus/proxy_service_spec.rb +++ b/spec/services/prometheus/proxy_service_spec.rb @@ -131,7 +131,7 @@ describe Prometheus::ProxyService do allow(environment).to receive(:prometheus_adapter) .and_return(prometheus_adapter) allow(prometheus_adapter).to receive(:can_query?).and_return(true) - allow(prometheus_adapter).to receive(:prometheus_client_wrapper) + allow(prometheus_adapter).to receive(:prometheus_client) .and_return(prometheus_client) end diff --git a/spec/support/matchers/be_url.rb b/spec/support/matchers/be_url.rb index 7bd0e7fada4..69171f53891 100644 --- a/spec/support/matchers/be_url.rb +++ b/spec/support/matchers/be_url.rb @@ -5,3 +5,7 @@ RSpec::Matchers.define :be_url do |_| URI.parse(actual) rescue false end end + +# looks better when used like: +# expect(thing).to receive(:method).with(a_valid_url) +RSpec::Matchers.alias_matcher :a_valid_url, :be_url diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb index 82582630dee..4e006edb7da 100644 --- a/spec/support/prometheus/additional_metrics_shared_examples.rb +++ b/spec/support/prometheus/additional_metrics_shared_examples.rb @@ -50,7 +50,7 @@ RSpec.shared_examples 'additional metrics query' do let!(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:project) { cluster.project } let(:environment) { create(:environment, slug: 'environment-slug', project: project) } - let(:kube_namespace) { project.deployment_platform.kubernetes_namespace_for(project) } + let(:kube_namespace) { environment.deployment_namespace } it_behaves_like 'query context containing environment slug and filter' diff --git a/spec/support/services/clusters/create_service_shared.rb b/spec/support/services/clusters/create_service_shared.rb index 6ec8750ce87..27f6d0570b6 100644 --- a/spec/support/services/clusters/create_service_shared.rb +++ b/spec/support/services/clusters/create_service_shared.rb @@ -32,23 +32,56 @@ shared_context 'invalid cluster create params' do end shared_examples 'create cluster service success' do - it 'creates a cluster object and performs a worker' do - expect(ClusterProvisionWorker).to receive(:perform_async) - - expect { subject } - .to change { Clusters::Cluster.count }.by(1) - .and change { Clusters::Providers::Gcp.count }.by(1) - - expect(subject.name).to eq('test-cluster') - expect(subject.user).to eq(user) - expect(subject.project).to eq(project) - expect(subject.provider.gcp_project_id).to eq('gcp-project') - expect(subject.provider.zone).to eq('us-central1-a') - expect(subject.provider.num_nodes).to eq(1) - expect(subject.provider.machine_type).to eq('machine_type-a') - expect(subject.provider.access_token).to eq(access_token) - expect(subject.provider).to be_legacy_abac - expect(subject.platform).to be_nil + context 'namespace per environment feature is enabled' do + before do + stub_feature_flags(kubernetes_namespace_per_environment: true) + end + + it 'creates a cluster object and performs a worker' do + expect(ClusterProvisionWorker).to receive(:perform_async) + + expect { subject } + .to change { Clusters::Cluster.count }.by(1) + .and change { Clusters::Providers::Gcp.count }.by(1) + + expect(subject.name).to eq('test-cluster') + expect(subject.user).to eq(user) + expect(subject.project).to eq(project) + expect(subject.provider.gcp_project_id).to eq('gcp-project') + expect(subject.provider.zone).to eq('us-central1-a') + expect(subject.provider.num_nodes).to eq(1) + expect(subject.provider.machine_type).to eq('machine_type-a') + expect(subject.provider.access_token).to eq(access_token) + expect(subject.provider).to be_legacy_abac + expect(subject.platform).to be_nil + expect(subject.namespace_per_environment).to eq true + end + end + + context 'namespace per environment feature is disabled' do + before do + stub_feature_flags(kubernetes_namespace_per_environment: false) + end + + it 'creates a cluster object and performs a worker' do + expect(ClusterProvisionWorker).to receive(:perform_async) + + expect { subject } + .to change { Clusters::Cluster.count }.by(1) + .and change { Clusters::Providers::Gcp.count }.by(1) + + expect(subject.name).to eq('test-cluster') + expect(subject.user).to eq(user) + expect(subject.project).to eq(project) + expect(subject.provider.gcp_project_id).to eq('gcp-project') + expect(subject.provider.zone).to eq('us-central1-a') + expect(subject.provider.num_nodes).to eq(1) + expect(subject.provider.machine_type).to eq('machine_type-a') + expect(subject.provider.access_token).to eq(access_token) + expect(subject.provider).to be_legacy_abac + expect(subject.platform).to be_nil + expect(subject.namespace_per_environment).to eq false + end end end diff --git a/yarn.lock b/yarn.lock index acf1a4d8652..b35f23c2791 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1687,6 +1687,14 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" +anymatch@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.0.3.tgz#2fb624fe0e84bccab00afee3d0006ed310f22f09" + integrity sha512-c6IvoeBECQlMVuYUjSwimnhmztImpErfxJzWZhIQinIvQWoGOnB0dLIgifbPHQt5heS6mNlaZG16f06H3C8t1g== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + apollo-cache-inmemory@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.5.1.tgz#265d1ee67b0bf0aca9c37629d410bfae44e62953" @@ -1857,11 +1865,6 @@ array-flatten@^2.1.0: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296" integrity sha1-Qmu52oQJDBg42BLIFQryCoMx4pY= -array-slice@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" - integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= - array-union@^1.0.1, array-union@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -1874,11 +1877,6 @@ array-uniq@^1.0.1, array-uniq@^1.0.2: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -1952,12 +1950,12 @@ async@^1.5.2: resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= -async@^2.0.0, async@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" - integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== dependencies: - lodash "^4.17.11" + lodash "^4.17.14" asynckit@^0.4.0: version "0.4.0" @@ -2189,6 +2187,11 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" integrity sha1-RqoXUftqL5PuXmibsQh9SxTGwgU= +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + binaryextensions@2: version "2.1.1" resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" @@ -2291,13 +2294,6 @@ brace-expansion@^1.1.7, brace-expansion@^1.1.8: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^0.1.2: - version "0.1.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-0.1.5.tgz#c085711085291d8b75fdd74eab0f8597280711e6" - integrity sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY= - dependencies: - expand-range "^0.1.0" - braces@^2.3.0, braces@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" @@ -2314,7 +2310,7 @@ braces@^2.3.0, braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1: +braces@^3.0.1, braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -2735,7 +2731,7 @@ check-types@^7.3.0: resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.3.0.tgz#468f571a4435c24248f5fd0cb0e8d87c3c341e7d" integrity sha1-Ro9XGkQ1wkJI9f0MsOjYfDw0Hn0= -chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0.4: +chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== @@ -2755,6 +2751,21 @@ chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0.4: optionalDependencies: fsevents "^1.2.2" +chokidar@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.0.2.tgz#0d1cd6d04eb2df0327446188cd13736a3367d681" + integrity sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA== + dependencies: + anymatch "^3.0.1" + braces "^3.0.2" + glob-parent "^5.0.0" + is-binary-path "^2.1.0" + is-glob "^4.0.1" + normalize-path "^3.0.0" + readdirp "^3.1.1" + optionalDependencies: + fsevents "^2.0.6" + chownr@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" @@ -2790,11 +2801,6 @@ circular-json@^0.3.1: resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== -circular-json@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.5.tgz#64182ef359042d37cd8e767fc9de878b1e9447d3" - integrity sha512-13YaR6kiz0kBNmIVM87Io8Hp7bWOo4r61vkEANy8iH9R9bc6avud/1FT0SBpqR1RpIQADOh/Q+yHZDA1iL6ysA== - class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -2866,6 +2872,15 @@ clone-buffer@^1.0.0: resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + clone-regexp@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f" @@ -2968,13 +2983,6 @@ colors@^1.1.0: resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== -combine-lists@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/combine-lists/-/combine-lists-1.0.1.tgz#458c07e09e0d900fc28b70a3fec2dacd1d2cb7f6" - integrity sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y= - dependencies: - lodash "^4.5.0" - combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" @@ -3002,10 +3010,10 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -compare-versions@^3.2.1: - version "3.4.0" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26" - integrity sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg== +compare-versions@^3.4.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.5.1.tgz#26e1f5cf0d48a77eced5046b9f67b6b61075a393" + integrity sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg== component-bind@1.0.0: version "1.0.0" @@ -3235,16 +3243,16 @@ core-js-pure@3.1.4: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.4.tgz#5fa17dc77002a169a3566cc48dc774d2e13e3769" integrity sha512-uJ4Z7iPNwiu1foygbcZYJsJs1jiXrTTCvxfLDXNhI/I+NHbSIEyr548y4fcsCEyWY0XgfAG/qqaunJ1SThHenA== -core-js@^2.2.0, core-js@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" - integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= - core-js@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.3.tgz#95700bca5f248f5f78c0ec63e784eca663ec4138" integrity sha512-PWZ+ZfuaKf178BIAg+CRsljwjIMRV8MY00CbZczkR6Zk5LfkSkjGoaab3+bqRQWVITNZxQB7TFYz+CFcyuamvA== +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -3799,10 +3807,10 @@ data-urls@^1.0.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" -date-format@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/date-format/-/date-format-1.2.0.tgz#615e828e233dd1ab9bb9ae0950e0ceccfa6ecad8" - integrity sha1-YV6CjiM90aubua4JUODOzPpuytg= +date-format@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf" + integrity sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA== date-now@^0.1.4: version "0.1.4" @@ -4862,15 +4870,6 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= -expand-braces@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea" - integrity sha1-SIsdHSRRyz06axks/AMPRMWFX+o= - dependencies: - array-slice "^0.2.3" - array-unique "^0.2.1" - braces "^0.1.2" - expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -4884,14 +4883,6 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expand-range@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-0.1.1.tgz#4cb8eda0993ca56fa4f41fc42f3cbb4ccadff044" - integrity sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ= - dependencies: - is-number "^0.1.1" - repeat-string "^0.2.2" - expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" @@ -5315,12 +5306,14 @@ from2@^2.1.0, from2@^2.1.1: inherits "^2.0.1" readable-stream "^2.0.0" -fs-access@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" - integrity sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o= +fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== dependencies: - null-check "^1.0.0" + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" fs-minipass@^1.2.5: version "1.2.6" @@ -5360,6 +5353,11 @@ fsevents@^1.2.2, fsevents@^1.2.7: nan "^2.12.1" node-pre-gyp "^0.12.0" +fsevents@^2.0.6: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a" + integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ== + fstream@^1.0.0, fstream@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" @@ -5514,6 +5512,13 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-parent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" + integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== + dependencies: + is-glob "^4.0.1" + glob-stream@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4" @@ -6382,6 +6387,13 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" +is-binary-path@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-buffer@^1.1.4, is-buffer@^1.1.5, is-buffer@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -6541,11 +6553,6 @@ is-npm@^1.0.0: resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ= -is-number@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" - integrity sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY= - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -6741,38 +6748,38 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul-api@^2.0.5: - version "2.1.1" - resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.1.1.tgz#194b773f6d9cbc99a9258446848b0f988951c4d0" - integrity sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw== +istanbul-api@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.1.6.tgz#d61702a9d1c66ad89d92e66d401e16b0bda4a35f" + integrity sha512-x0Eicp6KsShG1k1rMgBAi/1GgY7kFGEBwQpw3PXGEmu+rBcBNhqU8g2DgY9mlepAsLPzrzrbqSgCGANnki4POA== dependencies: - async "^2.6.1" - compare-versions "^3.2.1" + async "^2.6.2" + compare-versions "^3.4.0" fileset "^2.0.3" - istanbul-lib-coverage "^2.0.3" - istanbul-lib-hook "^2.0.3" - istanbul-lib-instrument "^3.1.0" - istanbul-lib-report "^2.0.4" - istanbul-lib-source-maps "^3.0.2" - istanbul-reports "^2.1.1" - js-yaml "^3.12.0" - make-dir "^1.3.0" + istanbul-lib-coverage "^2.0.5" + istanbul-lib-hook "^2.0.7" + istanbul-lib-instrument "^3.3.0" + istanbul-lib-report "^2.0.8" + istanbul-lib-source-maps "^3.0.6" + istanbul-reports "^2.2.4" + js-yaml "^3.13.1" + make-dir "^2.1.0" minimatch "^3.0.4" once "^1.4.0" -istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.3, istanbul-lib-coverage@^2.0.5: +istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== -istanbul-lib-hook@^2.0.3: +istanbul-lib-hook@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz#c95695f383d4f8f60df1f04252a9550e15b5b133" integrity sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA== dependencies: append-transform "^1.0.0" -istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.1.0: +istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== @@ -6785,7 +6792,7 @@ istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1, istanbul-lib-ins istanbul-lib-coverage "^2.0.5" semver "^6.0.0" -istanbul-lib-report@^2.0.4: +istanbul-lib-report@^2.0.4, istanbul-lib-report@^2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== @@ -6794,7 +6801,7 @@ istanbul-lib-report@^2.0.4: make-dir "^2.1.0" supports-color "^6.1.0" -istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.2: +istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== @@ -6805,7 +6812,7 @@ istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.2: rimraf "^2.6.3" source-map "^0.6.1" -istanbul-reports@^2.1.1: +istanbul-reports@^2.1.1, istanbul-reports@^2.2.4: version "2.2.6" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.6.tgz#7b4f2660d82b29303a8fe6091f8ca4bf058da1af" integrity sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA== @@ -7415,6 +7422,13 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -7446,20 +7460,19 @@ jszip@^3.1.3: pako "~1.0.2" readable-stream "~2.0.6" -karma-chrome-launcher@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf" - integrity sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w== +karma-chrome-launcher@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.0.0.tgz#5c3a7f877a304e90781c28fcd9a49e334a890f42" + integrity sha512-u/PnVgDOP97AUe/gJeABlC6Wa6aQ83MZsm0JgsJQ5bGQ9XcXON/7b2aRhl59A62Zom+q3PFveBkczc7E1RT7TA== dependencies: - fs-access "^1.0.0" which "^1.2.1" -karma-coverage-istanbul-reporter@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.4.tgz#402ae4ed6eadb9d9dafbd408ffda17897c0d003a" - integrity sha512-xJS7QSQIVU6VK9HuJ/ieE5yynxKhjCCkd96NLY/BX/HXsx0CskU9JJiMQbd4cHALiddMwI4OWh1IIzeWrsavJw== +karma-coverage-istanbul-reporter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.1.0.tgz#5f1bcc13c5e14ee1d91821ee8946861674f54c75" + integrity sha512-UH0mXPJFJyK5uiK7EkwGtQ8f30lCBAfqRResnZ4pzLJ04SOp4SPlYkmwbbZ6iVJ6sQFVzlDUXlntBEsLRdgZpg== dependencies: - istanbul-api "^2.0.5" + istanbul-api "^2.1.6" minimatch "^3.0.4" karma-jasmine@^1.1.2: @@ -7491,38 +7504,39 @@ karma-sourcemap-loader@^0.3.7: dependencies: graceful-fs "^4.1.2" -karma-webpack@^4.0.0-beta.0: - version "4.0.0-rc.2" - resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-4.0.0-rc.2.tgz#4c194e94789842af7f0ffa0de77ee7715739c7c1" - integrity sha512-Wuiq/xFBsbJMsHhYy5SYXxSp7Q0b8uzAG8+Siuo56ntoi5GluPE5LK3Mzl2UtD4k1leFwL6IeIE6Q+tk4F6k9Q== +karma-webpack@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-4.0.2.tgz#23219bd95bdda853e3073d3874d34447c77bced0" + integrity sha512-970/okAsdUOmiMOCY8sb17A2I8neS25Ad9uhyK3GHgmRSIFJbDcNEFE8dqqUhNe9OHiCC9k3DMrSmtd/0ymP1A== dependencies: - async "^2.0.0" + clone-deep "^4.0.1" loader-utils "^1.1.0" - lodash "^4.17.10" - source-map "^0.5.6" - webpack-dev-middleware "^3.2.0" + neo-async "^2.6.1" + schema-utils "^1.0.0" + source-map "^0.7.3" + webpack-dev-middleware "^3.7.0" -karma@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/karma/-/karma-3.0.0.tgz#6da83461a8a28d8224575c3b5b874e271b4730c3" - integrity sha512-ZTjyuDXVXhXsvJ1E4CnZzbCjSxD6sEdzEsFYogLuZM0yqvg/mgz+O+R1jb0J7uAQeuzdY8kJgx6hSNXLwFuHIQ== +karma@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/karma/-/karma-4.2.0.tgz#27e88b310cde090d016980ff5444e3a239196fca" + integrity sha512-fmCuxN1rwJxTdZfOXK5LjlmS4Ana/OvzNMpkyLL/TLE8hmgSkpVpMYQ7RTVa8TNKRVQDZNl5W1oF5cfKfgIMlA== dependencies: bluebird "^3.3.0" body-parser "^1.16.1" - chokidar "^2.0.3" + braces "^3.0.2" + chokidar "^3.0.0" colors "^1.1.0" - combine-lists "^1.0.0" connect "^3.6.0" - core-js "^2.2.0" + core-js "^3.1.3" di "^0.0.1" dom-serialize "^2.2.0" - expand-braces "^0.1.1" + flatted "^2.0.0" glob "^7.1.1" graceful-fs "^4.1.2" http-proxy "^1.13.0" isbinaryfile "^3.0.0" - lodash "^4.17.4" - log4js "^3.0.0" + lodash "^4.17.11" + log4js "^4.0.0" mime "^2.3.1" minimatch "^3.0.2" optimist "^0.6.1" @@ -7533,7 +7547,7 @@ karma@^3.0.0: socket.io "2.1.1" source-map "^0.6.1" tmp "0.0.33" - useragent "2.2.1" + useragent "2.3.0" katex@^0.10.0: version "0.10.0" @@ -7788,7 +7802,7 @@ lodash.upperfirst@4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984= -lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.5.0, lodash@~4.17.10: +lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -7807,16 +7821,16 @@ log-symbols@^3.0.0: dependencies: chalk "^2.4.2" -log4js@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-3.0.5.tgz#b80146bfebad68b430d4f3569556d8a6edfef303" - integrity sha512-IX5c3G/7fuTtdr0JjOT2OIR12aTESVhsH6cEsijloYwKgcPRlO6DgOU72v0UFhWcoV1HN6+M3dwT89qVPLXm0w== +log4js@^4.0.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-4.5.1.tgz#e543625e97d9e6f3e6e7c9fc196dd6ab2cae30b5" + integrity sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw== dependencies: - circular-json "^0.5.5" - date-format "^1.2.0" - debug "^3.1.0" - rfdc "^1.1.2" - streamroller "0.7.0" + date-format "^2.0.0" + debug "^4.1.1" + flatted "^2.0.0" + rfdc "^1.1.4" + streamroller "^1.0.6" loglevel@^1.4.1: version "1.4.1" @@ -7861,15 +7875,10 @@ lowlight@^1.11.0: fault "^1.0.2" highlight.js "~9.13.0" -lru-cache@2.2.x: - version "2.2.4" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d" - integrity sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0= - -lru-cache@^4.0.1, lru-cache@^4.1.2, lru-cache@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" - integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA== +lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.2, lru-cache@^4.1.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== dependencies: pseudomap "^1.0.2" yallist "^2.1.2" @@ -7886,7 +7895,7 @@ lz-string@^1.4.4: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY= -make-dir@^1.0.0, make-dir@^1.3.0: +make-dir@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== @@ -8072,7 +8081,7 @@ memory-fs@^0.2.0: resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" integrity sha1-8rslNovBIeORwlIN6Slpyu4KApA= -memory-fs@^0.4.0, memory-fs@~0.4.1: +memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= @@ -8210,7 +8219,7 @@ mime@1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== -mime@^2.0.3, mime@^2.2.0, mime@^2.3.1: +mime@^2.0.3, mime@^2.2.0, mime@^2.3.1, mime@^2.4.2: version "2.4.4" resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== @@ -8457,10 +8466,10 @@ negotiator@0.6.1: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= -neo-async@^2.5.0, neo-async@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" - integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== +neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== nice-try@^1.0.4: version "1.0.5" @@ -8729,11 +8738,6 @@ npm-run-path@^2.0.0: gauge "~2.7.3" set-blocking "~2.0.0" -null-check@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" - integrity sha1-l33/1xdgErnsMNKjnbXPcqBDnt0= - num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" @@ -9288,7 +9292,7 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.5: +picomatch@^2.0.4, picomatch@^2.0.5: version "2.0.7" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== @@ -9918,10 +9922,10 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= +range-parser@^1.0.3, range-parser@^1.2.0, range-parser@^1.2.1, range-parser@~1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== raphael@^2.2.7: version "2.2.7" @@ -10035,7 +10039,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -10100,6 +10104,13 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" +readdirp@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.1.tgz#b158123ac343c8b0f31d65680269cc0fc1025db1" + integrity sha512-XXdSXZrQuvqoETj50+JAitxz1UPdt5dupjT6T5nVB+WvjMv2XKYj+s7hPeAVCXvmJrL36O4YYyWlIC3an2ePiQ== + dependencies: + picomatch "^2.0.4" + realpath-native@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" @@ -10393,11 +10404,6 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== -repeat-string@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-0.2.2.tgz#c7a8d3236068362059a7e4651fc6884e8b1fb4ae" - integrity sha1-x6jTI2BoNiBZp+RlH8aITosftK4= - repeat-string@^1.5.0, repeat-string@^1.5.4, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" @@ -10566,10 +10572,10 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -rfdc@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" - integrity sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA== +rfdc@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2" + integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug== rimraf@2, rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.3: version "2.6.3" @@ -10878,6 +10884,13 @@ sha1@^1.1.1: charenc ">= 0.0.1" crypt ">= 0.0.1" +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -11114,6 +11127,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + space-separated-tokens@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.4.tgz#27910835ae00d0adfcdbd0ad7e611fb9544351fa" @@ -11303,15 +11321,16 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= -streamroller@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-0.7.0.tgz#a1d1b7cf83d39afb0d63049a5acbf93493bdf64b" - integrity sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ== +streamroller@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-1.0.6.tgz#8167d8496ed9f19f05ee4b158d9611321b8cacd9" + integrity sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg== dependencies: - date-format "^1.2.0" - debug "^3.1.0" - mkdirp "^0.5.1" - readable-stream "^2.3.0" + async "^2.6.2" + date-format "^2.0.0" + debug "^3.2.6" + fs-extra "^7.0.1" + lodash "^4.17.14" strict-uri-encode@^1.0.0: version "1.1.0" @@ -12284,6 +12303,11 @@ unist-util-visit@^1.0.0, unist-util-visit@^1.1.0, unist-util-visit@^1.3.0: dependencies: unist-util-visit-parents "^2.0.0" +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -12394,12 +12418,12 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -useragent@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.2.1.tgz#cf593ef4f2d175875e8bb658ea92e18a4fd06d8e" - integrity sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4= +useragent@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972" + integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw== dependencies: - lru-cache "2.2.x" + lru-cache "4.1.x" tmp "0.0.x" util-deprecate@^1.0.1, util-deprecate@~1.0.1: @@ -12781,7 +12805,7 @@ webpack-cli@^3.2.1: v8-compile-cache "^2.0.2" yargs "^12.0.4" -webpack-dev-middleware@3.4.0, webpack-dev-middleware@^3.2.0: +webpack-dev-middleware@3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890" integrity sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA== @@ -12791,6 +12815,16 @@ webpack-dev-middleware@3.4.0, webpack-dev-middleware@^3.2.0: range-parser "^1.0.3" webpack-log "^2.0.0" +webpack-dev-middleware@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz#ef751d25f4e9a5c8a35da600c5fda3582b5c6cff" + integrity sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.2" + range-parser "^1.2.1" + webpack-log "^2.0.0" + webpack-dev-server@^3.1.14: version "3.1.14" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz#60fb229b997fc5a0a1fc6237421030180959d469" |