Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-09-23 15:11:29 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-23 15:11:29 +0300
commit8c4e384860c39494c3436b7d6f3567458f79f0d9 (patch)
tree5d12275772ad85ba7ed108ebb0db7f30f193030c
parent66e4d1bf78b3ec2075135173b12767692ced242c (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/ide/components/jobs/detail.vue14
-rw-r--r--app/assets/javascripts/lib/logger/hello.js29
-rw-r--r--app/helpers/ci/jobs_helper.rb2
-rw-r--r--app/models/ci/bridge.rb6
-rw-r--r--app/models/namespace.rb8
-rw-r--r--app/models/namespaces/user_namespace.rb2
-rw-r--r--app/models/operations/feature_flag.rb30
-rw-r--r--app/models/operations/feature_flag_scope.rb66
-rw-r--r--app/models/user.rb6
-rw-r--r--app/serializers/feature_flag_entity.rb4
-rw-r--r--app/serializers/feature_flag_scope_entity.rb12
-rw-r--r--app/workers/all_queues.yml9
-rw-r--r--app/workers/ci/create_downstream_pipeline_worker.rb19
-rw-r--r--config/feature_flags/development/create_cross_project_pipeline_worker_rename.yml8
-rw-r--r--config/initializers/carrierwave_patch.rb10
-rw-r--r--doc/development/index.md1
-rw-r--r--doc/development/redis.md5
-rw-r--r--doc/development/redis/new_redis_instance.md131
-rw-r--r--doc/development/testing_guide/end_to_end/rspec_metadata_tests.md1
-rw-r--r--doc/user/admin_area/index.md8
-rw-r--r--lib/api/entities/feature_flag.rb4
-rw-r--r--lib/api/entities/feature_flag/detailed_legacy_scope.rb11
-rw-r--r--lib/api/entities/feature_flag/legacy_scope.rb16
-rw-r--r--lib/banzai/filter/front_matter_filter.rb2
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb5
-rw-r--r--locale/gitlab.pot27
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/composer_registry_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/generic_repository_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/helm_registry_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/rubygems_registry_spec.rb6
-rw-r--r--spec/factories/namespaces/user_namespaces.rb8
-rw-r--r--spec/frontend/ide/components/jobs/detail_spec.js24
-rw-r--r--spec/frontend/lib/logger/__snapshots__/hello_spec.js.snap21
-rw-r--r--spec/frontend/lib/logger/hello_spec.js28
-rw-r--r--spec/initializers/carrierwave_patch_spec.rb21
-rw-r--r--spec/lib/banzai/filter/front_matter_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb8
-rw-r--r--spec/lib/banzai/pipeline/pre_process_pipeline_spec.rb2
-rw-r--r--spec/models/ci/bridge_spec.rb56
-rw-r--r--spec/models/namespace_spec.rb14
-rw-r--r--spec/models/namespaces/user_namespace_spec.rb12
-rw-r--r--spec/models/operations/feature_flag_spec.rb25
-rw-r--r--spec/models/user_spec.rb96
-rw-r--r--spec/services/ci/play_bridge_service_spec.rb30
-rw-r--r--spec/tooling/danger/project_helper_spec.rb3
-rw-r--r--spec/workers/ci/create_downstream_pipeline_worker_spec.rb37
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb1
-rw-r--r--tooling/danger/project_helper.rb1
57 files changed, 558 insertions, 343 deletions
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 9dafbf994eb..12e42d263a9 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-13.21.0
+13.21.1
diff --git a/Gemfile b/Gemfile
index d94174cc094..90ae478dd4b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -129,7 +129,7 @@ gem 'fog-local', '~> 0.6'
gem 'fog-openstack', '~> 1.0'
gem 'fog-rackspace', '~> 0.1.1'
gem 'fog-aliyun', '~> 0.3'
-gem 'gitlab-fog-azure-rm', '~> 1.1.1', require: false
+gem 'gitlab-fog-azure-rm', '~> 1.2.0', require: false
# for Google storage
gem 'google-api-client', '~> 0.33'
diff --git a/Gemfile.lock b/Gemfile.lock
index 88506372707..ca0ffd6093f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -467,7 +467,7 @@ GEM
activesupport (>= 3.0)
request_store (>= 1.0)
scientist (~> 1.6, >= 1.6.0)
- gitlab-fog-azure-rm (1.1.1)
+ gitlab-fog-azure-rm (1.2.0)
azure-storage-blob (~> 2.0)
azure-storage-common (~> 2.0)
fog-core (= 2.1.0)
@@ -1466,7 +1466,7 @@ DEPENDENCIES
gitlab-chronic (~> 0.10.5)
gitlab-dangerfiles (~> 2.3.0)
gitlab-experiment (~> 0.6.4)
- gitlab-fog-azure-rm (~> 1.1.1)
+ gitlab-fog-azure-rm (~> 1.2.0)
gitlab-labkit (~> 0.21.1)
gitlab-license (~> 2.0)
gitlab-mail_room (~> 0.0.9)
diff --git a/app/assets/javascripts/ide/components/jobs/detail.vue b/app/assets/javascripts/ide/components/jobs/detail.vue
index c142992a9d1..cc54dd52561 100644
--- a/app/assets/javascripts/ide/components/jobs/detail.vue
+++ b/app/assets/javascripts/ide/components/jobs/detail.vue
@@ -44,18 +44,18 @@ export default {
methods: {
...mapActions('pipelines', ['fetchJobLogs', 'setDetailJob']),
scrollDown() {
- if (this.$refs.buildTrace) {
- this.$refs.buildTrace.scrollTo(0, this.$refs.buildTrace.scrollHeight);
+ if (this.$refs.buildJobLog) {
+ this.$refs.buildJobLog.scrollTo(0, this.$refs.buildJobLog.scrollHeight);
}
},
scrollUp() {
- if (this.$refs.buildTrace) {
- this.$refs.buildTrace.scrollTo(0, 0);
+ if (this.$refs.buildJobLog) {
+ this.$refs.buildJobLog.scrollTo(0, 0);
}
},
scrollBuildLog: throttle(function buildLogScrollDebounce() {
- const { scrollTop } = this.$refs.buildTrace;
- const { offsetHeight, scrollHeight } = this.$refs.buildTrace;
+ const { scrollTop } = this.$refs.buildJobLog;
+ const { offsetHeight, scrollHeight } = this.$refs.buildJobLog;
if (scrollTop + offsetHeight === scrollHeight) {
this.scrollPos = scrollPositions.bottom;
@@ -97,7 +97,7 @@ export default {
<scroll-button :disabled="isScrolledToBottom" direction="down" @click="scrollDown" />
</div>
</div>
- <pre ref="buildTrace" class="build-trace mb-0 h-100 mr-3" @scroll="scrollBuildLog">
+ <pre ref="buildJobLog" class="build-trace mb-0 h-100 mr-3" @scroll="scrollBuildLog">
<code
v-show="!detailJob.isLoading"
class="bash"
diff --git a/app/assets/javascripts/lib/logger/hello.js b/app/assets/javascripts/lib/logger/hello.js
index 18fa35ab55b..ccfdfe91e60 100644
--- a/app/assets/javascripts/lib/logger/hello.js
+++ b/app/assets/javascripts/lib/logger/hello.js
@@ -1,15 +1,36 @@
+import { s__, sprintf } from '~/locale';
+
const HANDSHAKE = String.fromCodePoint(0x1f91d);
const MAG = String.fromCodePoint(0x1f50e);
+const ROCKET = String.fromCodePoint(0x1f680);
export const logHello = () => {
// eslint-disable-next-line no-console
console.log(
- `%cWelcome to GitLab!%c
+ `%c${s__('HelloMessage|Welcome to GitLab!')}%c
-Does this page need fixes or improvements? Open an issue or contribute a merge request to help make GitLab more lovable. At GitLab, everyone can contribute!
+${s__(
+ 'HelloMessage|Does this page need fixes or improvements? Open an issue or contribute a merge request to help make GitLab more lovable. At GitLab, everyone can contribute!',
+)}
-${HANDSHAKE} Contribute to GitLab: https://about.gitlab.com/community/contribute/
-${MAG} Create a new GitLab issue: https://gitlab.com/gitlab-org/gitlab/-/issues/new`,
+${sprintf(s__('HelloMessage|%{handshake_emoji} Contribute to GitLab: %{contribute_link}'), {
+ handshake_emoji: `${HANDSHAKE}`,
+ contribute_link: 'https://about.gitlab.com/community/contribute/',
+})}
+${sprintf(s__('HelloMessage|%{magnifier_emoji} Create a new GitLab issue: %{new_issue_link}'), {
+ magnifier_emoji: `${MAG}`,
+ new_issue_link: 'https://gitlab.com/gitlab-org/gitlab/-/issues/new',
+})}
+${
+ window.gon?.dot_com
+ ? `${sprintf(
+ s__(
+ 'HelloMessage|%{rocket_emoji} We like your curiosity! Help us improve GitLab by joining the team: %{jobs_page_link}',
+ ),
+ { rocket_emoji: `${ROCKET}`, jobs_page_link: 'https://about.gitlab.com/jobs/' },
+ )}`
+ : ''
+}`,
`padding-top: 0.5em; font-size: 2em;`,
'padding-bottom: 0.5em;',
);
diff --git a/app/helpers/ci/jobs_helper.rb b/app/helpers/ci/jobs_helper.rb
index 882302f05ad..d02fe3f20b0 100644
--- a/app/helpers/ci/jobs_helper.rb
+++ b/app/helpers/ci/jobs_helper.rb
@@ -7,7 +7,7 @@ module Ci
"endpoint" => project_job_path(@project, @build, format: :json),
"project_path" => @project.full_path,
"artifact_help_url" => help_page_path('user/gitlab_com/index.html', anchor: 'gitlab-cicd'),
- "deployment_help_url" => help_page_path('user/project/clusters/index.html', anchor: 'troubleshooting'),
+ "deployment_help_url" => help_page_path('user/project/clusters/deploy_to_cluster.html', anchor: 'troubleshooting'),
"runner_settings_url" => project_runners_path(@build.project, anchor: 'js-runners-settings'),
"page_path" => project_job_path(@project, @build),
"build_status" => @build.status,
diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb
index 97fb8233d34..29bedd07a55 100644
--- a/app/models/ci/bridge.rb
+++ b/app/models/ci/bridge.rb
@@ -31,7 +31,11 @@ module Ci
next unless bridge.triggers_downstream_pipeline?
bridge.run_after_commit do
- ::Ci::CreateCrossProjectPipelineWorker.perform_async(bridge.id)
+ if ::Feature.enabled?(:create_cross_project_pipeline_worker_rename, default_enabled: :yaml)
+ ::Ci::CreateDownstreamPipelineWorker.perform_async(bridge.id)
+ else
+ ::Ci::CreateCrossProjectPipelineWorker.perform_async(bridge.id)
+ end
end
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index b7895f6cbf3..3ffd377251c 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -101,7 +101,9 @@ class Namespace < ApplicationRecord
saved_change_to_name? || saved_change_to_path? || saved_change_to_parent_id?
}
- scope :for_user, -> { where(type: nil) }
+ # TODO: change to `type: Namespaces::UserNamespace.sti_name` when
+ # working on issue https://gitlab.com/gitlab-org/gitlab/-/issues/341070
+ scope :user_namespaces, -> { where(type: [nil, Namespaces::UserNamespace.sti_name]) }
scope :sort_by_type, -> { order(Gitlab::Database.nulls_first_order(:type)) }
scope :include_route, -> { includes(:route) }
scope :by_parent, -> (parent) { where(parent_id: parent) }
@@ -143,9 +145,7 @@ class Namespace < ApplicationRecord
when Namespaces::ProjectNamespace.sti_name
Namespaces::ProjectNamespace
when Namespaces::UserNamespace.sti_name
- # TODO: We create a normal Namespace until
- # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68894 is ready
- Namespace
+ Namespaces::UserNamespace
else
Namespace
end
diff --git a/app/models/namespaces/user_namespace.rb b/app/models/namespaces/user_namespace.rb
index 517d68b118d..22b7a0a3b2b 100644
--- a/app/models/namespaces/user_namespace.rb
+++ b/app/models/namespaces/user_namespace.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
# TODO: currently not created/mapped in the database, will be done in another issue
-# https://gitlab.com/gitlab-org/gitlab/-/issues/337102
+# https://gitlab.com/gitlab-org/gitlab/-/issues/341070
module Namespaces
class UserNamespace < Namespace
def self.sti_name
diff --git a/app/models/operations/feature_flag.rb b/app/models/operations/feature_flag.rb
index 46810749b18..28e8cf52d83 100644
--- a/app/models/operations/feature_flag.rb
+++ b/app/models/operations/feature_flag.rb
@@ -19,13 +19,10 @@ module Operations
default_value_for :active, true
default_value_for :version, :new_version_flag
- # scopes exists only for the first version
- has_many :scopes, class_name: 'Operations::FeatureFlagScope'
# strategies exists only for the second version
has_many :strategies, class_name: 'Operations::FeatureFlags::Strategy'
has_many :feature_flag_issues
has_many :issues, through: :feature_flag_issues
- has_one :default_scope, -> { where(environment_scope: '*') }, class_name: 'Operations::FeatureFlagScope'
validates :project, presence: true
validates :name,
@@ -37,10 +34,7 @@ module Operations
}
validates :name, uniqueness: { scope: :project_id }
validates :description, allow_blank: true, length: 0..255
- validate :first_default_scope, on: :create, if: :has_scopes?
- validate :version_associations
- accepts_nested_attributes_for :scopes, allow_destroy: true
accepts_nested_attributes_for :strategies, allow_destroy: true
scope :ordered, -> { order(:name) }
@@ -56,7 +50,7 @@ module Operations
class << self
def preload_relations
- preload(:scopes, strategies: :scopes)
+ preload(strategies: :scopes)
end
def for_unleash_client(project, environment)
@@ -119,27 +113,5 @@ module Operations
active: active
}
end
-
- private
-
- def version_associations
- if new_version_flag? && scopes.any?
- errors.add(:version_associations, 'version 2 feature flags may not have scopes')
- end
- end
-
- def first_default_scope
- unless scopes.first.environment_scope == '*'
- errors.add(:default_scope, 'has to be the first element')
- end
- end
-
- def build_default_scope
- scopes.build(environment_scope: '*', active: self.active)
- end
-
- def has_scopes?
- scopes.any?
- end
end
end
diff --git a/app/models/operations/feature_flag_scope.rb b/app/models/operations/feature_flag_scope.rb
deleted file mode 100644
index 9068ca0f588..00000000000
--- a/app/models/operations/feature_flag_scope.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# frozen_string_literal: true
-
-# All of the legacy flags have been removed in 14.1, including all of the
-# `operations_feature_flag_scopes` rows. Therefore, this model and the database
-# table are unused and should be removed.
-
-module Operations
- class FeatureFlagScope < ApplicationRecord
- prepend HasEnvironmentScope
- include Gitlab::Utils::StrongMemoize
-
- self.table_name = 'operations_feature_flag_scopes'
-
- belongs_to :feature_flag
-
- validates :environment_scope, uniqueness: {
- scope: :feature_flag,
- message: "(%{value}) has already been taken"
- }
-
- validates :environment_scope,
- if: :default_scope?, on: :update,
- inclusion: { in: %w(*), message: 'cannot be changed from default scope' }
-
- validates :strategies, feature_flag_strategies: true
-
- before_destroy :prevent_destroy_default_scope, if: :default_scope?
-
- scope :ordered, -> { order(:id) }
- scope :enabled, -> { where(active: true) }
- scope :disabled, -> { where(active: false) }
-
- def self.with_name_and_description
- joins(:feature_flag)
- .select(FeatureFlag.arel_table[:name], FeatureFlag.arel_table[:description])
- end
-
- def self.for_unleash_client(project, environment)
- select_columns = [
- 'DISTINCT ON (operations_feature_flag_scopes.feature_flag_id) operations_feature_flag_scopes.id',
- '(operations_feature_flags.active AND operations_feature_flag_scopes.active) AS active',
- 'operations_feature_flag_scopes.strategies',
- 'operations_feature_flag_scopes.environment_scope',
- 'operations_feature_flag_scopes.created_at',
- 'operations_feature_flag_scopes.updated_at'
- ]
-
- select(select_columns)
- .with_name_and_description
- .where(feature_flag_id: project.operations_feature_flags.select(:id))
- .order(:feature_flag_id)
- .on_environment(environment)
- .reverse_order
- end
-
- private
-
- def default_scope?
- environment_scope_was == '*'
- end
-
- def prevent_destroy_default_scope
- raise ActiveRecord::ReadOnlyRecord, "default scope cannot be destroyed"
- end
- end
-end
diff --git a/app/models/user.rb b/app/models/user.rb
index 311712bba1e..ae75e0f8011 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -112,7 +112,9 @@ class User < ApplicationRecord
#
# Namespace for personal projects
- has_one :namespace, -> { where(type: nil) }, dependent: :destroy, foreign_key: :owner_id, inverse_of: :owner, autosave: true # rubocop:disable Cop/ActiveRecordDependent
+ # TODO: change to `type: Namespaces::UserNamespace.sti_name` when
+ # working on issue https://gitlab.com/gitlab-org/gitlab/-/issues/341070
+ has_one :namespace, -> { where(type: [nil, Namespaces::UserNamespace.sti_name]) }, dependent: :destroy, foreign_key: :owner_id, inverse_of: :owner, autosave: true # rubocop:disable Cop/ActiveRecordDependent
# Profile
has_many :keys, -> { regular_keys }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -728,7 +730,7 @@ class User < ApplicationRecord
end
def find_by_full_path(path, follow_redirects: false)
- namespace = Namespace.for_user.find_by_full_path(path, follow_redirects: follow_redirects)
+ namespace = Namespace.user_namespaces.find_by_full_path(path, follow_redirects: follow_redirects)
namespace&.owner
end
diff --git a/app/serializers/feature_flag_entity.rb b/app/serializers/feature_flag_entity.rb
index 80cf869a389..196a4cd504f 100644
--- a/app/serializers/feature_flag_entity.rb
+++ b/app/serializers/feature_flag_entity.rb
@@ -24,8 +24,8 @@ class FeatureFlagEntity < Grape::Entity
project_feature_flag_path(feature_flag.project, feature_flag)
end
- expose :scopes, with: FeatureFlagScopeEntity do |feature_flag|
- feature_flag.scopes.sort_by(&:id)
+ expose :scopes do |_ff|
+ []
end
expose :strategies, with: FeatureFlags::StrategyEntity do |feature_flag|
diff --git a/app/serializers/feature_flag_scope_entity.rb b/app/serializers/feature_flag_scope_entity.rb
deleted file mode 100644
index 0450797a545..00000000000
--- a/app/serializers/feature_flag_scope_entity.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-class FeatureFlagScopeEntity < Grape::Entity
- include RequestAwareEntity
-
- expose :id
- expose :active
- expose :environment_scope
- expose :created_at
- expose :updated_at
- expose :strategies
-end
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 0a600666ccd..281889153be 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -1474,6 +1474,15 @@
:weight: 3
:idempotent:
:tags: []
+- :name: pipeline_default:ci_create_downstream_pipeline
+ :worker_name: Ci::CreateDownstreamPipelineWorker
+ :feature_category: :continuous_integration
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :cpu
+ :weight: 3
+ :idempotent:
+ :tags: []
- :name: pipeline_default:ci_drop_pipeline
:worker_name: Ci::DropPipelineWorker
:feature_category: :continuous_integration
diff --git a/app/workers/ci/create_downstream_pipeline_worker.rb b/app/workers/ci/create_downstream_pipeline_worker.rb
new file mode 100644
index 00000000000..6d4cd2539c1
--- /dev/null
+++ b/app/workers/ci/create_downstream_pipeline_worker.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Ci
+ class CreateDownstreamPipelineWorker # rubocop:disable Scalability/IdempotentWorker
+ include ::ApplicationWorker
+ include ::PipelineQueue
+
+ sidekiq_options retry: 3
+ worker_resource_boundary :cpu
+
+ def perform(bridge_id)
+ ::Ci::Bridge.find_by_id(bridge_id).try do |bridge|
+ ::Ci::CreateDownstreamPipelineService
+ .new(bridge.project, bridge.user)
+ .execute(bridge)
+ end
+ end
+ end
+end
diff --git a/config/feature_flags/development/create_cross_project_pipeline_worker_rename.yml b/config/feature_flags/development/create_cross_project_pipeline_worker_rename.yml
new file mode 100644
index 00000000000..c9df20e93b5
--- /dev/null
+++ b/config/feature_flags/development/create_cross_project_pipeline_worker_rename.yml
@@ -0,0 +1,8 @@
+---
+name: create_cross_project_pipeline_worker_rename
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70816
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/341410
+milestone: '14.4'
+type: development
+group: group::pipeline authoring
+default_enabled: false
diff --git a/config/initializers/carrierwave_patch.rb b/config/initializers/carrierwave_patch.rb
index c8c6f75949c..a9c74478541 100644
--- a/config/initializers/carrierwave_patch.rb
+++ b/config/initializers/carrierwave_patch.rb
@@ -49,14 +49,8 @@ module CarrierWave
local_file = local_directory.files.new(key: path)
expire_at = options[:expire_at] || ::Fog::Time.now + @uploader.fog_authenticated_url_expiration
case @uploader.fog_credentials[:provider]
- when 'AWS', 'Google'
- # Older versions of fog-google do not support options as a parameter
- if url_options_supported?(local_file)
- local_file.url(expire_at, options)
- else
- warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
- local_file.url(expire_at)
- end
+ when 'AWS', 'Google', 'AzureRM'
+ local_file.url(expire_at, options)
when 'Rackspace'
connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
when 'OpenStack'
diff --git a/doc/development/index.md b/doc/development/index.md
index 7283d1a30f7..58fb5d83ba8 100644
--- a/doc/development/index.md
+++ b/doc/development/index.md
@@ -215,6 +215,7 @@ the [reviewer values](https://about.gitlab.com/handbook/engineering/workflow/rev
- [How to dump production data to staging](db_dump.md)
- [Geo development](geo.md)
- [Redis guidelines](redis.md)
+ - [Adding a new Redis instance](redis/new_redis_instance.md)
- [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
- [Working with Gitaly](gitaly.md)
- [Elasticsearch integration docs](elasticsearch.md)
diff --git a/doc/development/redis.md b/doc/development/redis.md
index e631a6ec80c..13ec923c19a 100644
--- a/doc/development/redis.md
+++ b/doc/development/redis.md
@@ -6,11 +6,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Redis guidelines
+## Redis instances
+
GitLab uses [Redis](https://redis.io) for the following distinct purposes:
- Caching (mostly via `Rails.cache`).
- As a job processing queue with [Sidekiq](sidekiq_style_guide.md).
- To manage the shared application state.
+- To store CI trace chunks.
- As a Pub/Sub queue backend for ActionCable.
In most environments (including the GDK), all of these point to the same
@@ -29,6 +32,8 @@ more often than it is read.
If [Geo](geo.md) is enabled, each Geo node gets its own, independent Redis
database.
+We have [development documentation on adding a new Redis instance](redis/new_redis_instance.md).
+
## Key naming
Redis is a flat namespace with no hierarchy, which means we must pay attention
diff --git a/doc/development/redis/new_redis_instance.md b/doc/development/redis/new_redis_instance.md
new file mode 100644
index 00000000000..714936d9a24
--- /dev/null
+++ b/doc/development/redis/new_redis_instance.md
@@ -0,0 +1,131 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+---
+
+# Add a new Redis instance
+
+GitLab can make use of multiple [Redis instances](../redis.md#redis-instances).
+These instances are functionally partitioned so that, for example, we
+can store [CI trace chunks](../../administration/job_logs.md#incremental-logging-architecture)
+from one Redis instance while storing sessions in another.
+
+From time to time we might want to add a new Redis instance. Typically this will
+be a functional partition split from one of the existing instances such as the
+cache or shared state. This document describes an approach
+for adding a new Redis instance that handles existing data, based on
+prior examples:
+
+- [Dedicated Redis instance for Trace Chunk storage](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/462).
+
+This document does not cover the operational side of preparing and configuring
+the new Redis instance in detail, but the example epics do contain information
+on previous approaches to this.
+
+## Step 1: Support configuring the new instance
+
+Before we can switch any features to using the new instance, we have to support
+configuring it and referring to it in the codebase. We must support the
+main installation types:
+
+- Source installs (including development environments) - [example MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62767)
+- Omnibus - [example MR](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5316)
+- Helm charts - [example MR](https://gitlab.com/gitlab-org/charts/gitlab/-/merge_requests/2031)
+
+### Fallback instance
+
+In the application code, we need to define a fallback instance in case the new
+instance is not configured. For example, if a GitLab instance has already
+configured a separate shared state Redis, and we are partitioning data from the
+shared state Redis, our new instance's configuration should default to that of
+the shared state Redis when it's not present. Otherwise we could break instances
+that don't configure the new Redis instance as soon as it's available.
+
+You can [define a `.config_fallback` method](https://gitlab.com/gitlab-org/gitlab/-/blob/a75471dd744678f1a59eeb99f71fca577b155acd/lib/gitlab/redis/wrapper.rb#L69-87)
+in `Gitlab::Redis::Wrapper` (the base class for all Redis instances)
+that defines the instance to be used if this one is not configured. If we were
+adding a `Foo` instance that should fall back to `SharedState`, we can do that
+like this:
+
+```ruby
+module Gitlab
+ module Redis
+ class Foo < ::Gitlab::Redis::Wrapper
+ # The data we store on Foo used to be stored on SharedState.
+ def self.config_fallback
+ SharedState
+ end
+ end
+ end
+end
+```
+
+We should also add specs like those in
+[`trace_chunks_spec.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/lib/gitlab/redis/trace_chunks_spec.rb)
+to ensure that this fallback works correctly.
+
+## Step 2: Support writing to and reading from the new instance
+
+When migrating to the new instance, we must account for cases where data is
+either on:
+
+- The 'old' (original) instance.
+- The new one that we have just added support for.
+
+As a result we may need to support reading from and writing to both
+instances, depending on some condition.
+
+The exact condition to use varies depending on the data to be migrated. For
+the trace chunks case above, there was already a database column indicating where the
+data was stored (as there are other storage options than Redis).
+
+This step may not apply if the data has a very short lifetime (a few minutes at most)
+and is not critical. In that case, we
+may decide that it is OK to incur a small amount of data loss and switch
+over through configuration only.
+
+If there is not a more natural way to mark where the data is stored, using a
+[feature flag](../feature_flags/index.md) may be convenient:
+
+- It does not require an application restart to take effect.
+- It applies to all application instances (Sidekiq, API, web, etc.) at
+ the same time.
+- It supports incremental rollout - ideally by actor (project, group,
+ user, etc.) - so that we can monitor for errors and roll back easily.
+
+## Step 3: Migrate the data
+
+We then need to configure the new instance for GitLab.com's production and
+staging environments. Hopefully it will be possible to test this change
+effectively on staging, to at least make sure that basic usage continues to
+work.
+
+After that is done, we can roll out the change to production. Ideally this would
+be in an incremental fashion, following the
+[standard incremental rollout](../feature_flags/controls.md#rolling-out-changes)
+documentation for feature flags.
+
+When we have been using the new instance 100% of the time in production for a
+while and there are no issues, we can proceed.
+
+## Step 4: clean up after the migration
+
+<!-- markdownlint-disable MD044 -->
+We may choose to keep the migration paths or remove them, depending on whether
+or not we expect self-managed instances to perform this migration.
+[gitlab-com/gl-infra/scalability#1131](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1131#note_603354746)
+contains a discussion on this topic for the trace chunks feature flag. It may
+be - as in that case - that we decide that the maintenance costs of supporting
+the migration code are higher than the benefits of allowing self-managed
+instances to perform this migration seamlessly, if we expect self-managed
+instances to cope without this functional partition.
+<!-- markdownlint-enable MD044 -->
+
+If we decide to keep the migration code:
+
+- We should document the migration steps.
+- If we used a feature flag, we should ensure it's an [ops type feature
+ flag](../feature_flags/index.md#ops-type), as these are long-lived flags.
+
+Otherwise, we can remove the flags and conclude the project.
diff --git a/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md b/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md
index 35cd4f777b0..3749511fef5 100644
--- a/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md
+++ b/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md
@@ -26,6 +26,7 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec
| `:ldap_no_tls` | The test requires a GitLab instance to be configured to use an external LDAP server with TLS not enabled. |
| `:ldap_tls` | The test requires a GitLab instance to be configured to use an external LDAP server with TLS enabled. |
| `:mattermost` | The test requires a GitLab Mattermost service on the GitLab instance. |
+| `:mixed_env` | The test should only be executed in environments that have a paired canary version available through traffic routing based on the existence of the `gitlab_canary=true` cookie. Tests in this category are switching the cookie mid-test to validate mixed deployment environments. |
| `:object_storage` | The test requires a GitLab instance to be configured to use multiple [object storage types](../../../administration/object_storage.md). Uses MinIO as the object storage server. |
| `:only` | The test is only to be run in specific execution contexts. See [test execution context selection](execution_context_selection.md) for more information. |
| `:orchestrated` | The GitLab instance under test may be [configured by `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#orchestrated-tests) to be different to the default GitLab configuration, or `gitlab-qa` may launch additional services in separate Docker containers, or both. Tests tagged with `:orchestrated` are excluded when testing environments where we can't dynamically modify the GitLab configuration (for example, Staging). |
diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md
index 919914b5227..380e3f3dcc5 100644
--- a/doc/user/admin_area/index.md
+++ b/doc/user/admin_area/index.md
@@ -24,7 +24,7 @@ The Admin Area is made up of the following sections:
| Section | Description |
|:-----------------------------------------------|:------------|
-| **{overview}** [Overview](#overview-section) | View your GitLab [Dashboard](#admin-dashboard), and administer [projects](#administering-projects), [users](#administering-users), [groups](#administering-groups), [jobs](#administering-jobs), [runners](#administering-runners), and [Gitaly servers](#administering-gitaly-servers). |
+| **{overview}** [Overview](#overview-section) | View your GitLab [Dashboard](#admin-area-dashboard), and administer [projects](#administering-projects), [users](#administering-users), [groups](#administering-groups), [jobs](#administering-jobs), [runners](#administering-runners), and [Gitaly servers](#administering-gitaly-servers). |
| **{monitor}** Monitoring | View GitLab [system information](#system-information), and information on [background jobs](#background-jobs), [logs](#logs), [health checks](monitoring/health_check.md), [requests profiles](#requests-profiles), and [audit events](#audit-events). |
| **{messages}** Messages | Send and manage [broadcast messages](broadcast_messages.md) for your users. |
| **{hook}** System Hooks | Configure [system hooks](../../system_hooks/system_hooks.md) for many events. |
@@ -41,7 +41,7 @@ The Admin Area is made up of the following sections:
| **{appearance}** Appearance | Customize [GitLab appearance](appearance.md). |
| **{settings}** Settings | Modify the [settings](settings/index.md) for your GitLab instance. |
-## Admin Dashboard
+## Admin Area dashboard
The Dashboard provides statistics and system information about the GitLab instance.
@@ -151,7 +151,7 @@ you must provide the complete email address.
#### User impersonation
-An administrator can "impersonate" any other user, including other administrator users.
+An administrator can "impersonate" any other user, including other administrators.
This allows the administrator to "see what the user sees," and take actions on behalf of the user.
You can impersonate a user in the following ways:
@@ -369,7 +369,7 @@ The Sidekiq dashboard consists of the following elements:
### Logs
-Since GitLab 13.0, **Log** view has been removed from the admin dashboard since the logging does not work in multi-node setups and could cause confusion for administrators by displaying partial information.
+Since GitLab 13.0, **Log** view has been removed from the Admin Area dashboard since the logging does not work in multi-node setups and could cause confusion for administrators by displaying partial information.
For multi-node systems we recommend ingesting the logs into services like Elasticsearch and Splunk.
diff --git a/lib/api/entities/feature_flag.rb b/lib/api/entities/feature_flag.rb
index f383eabd5dc..9dec3873504 100644
--- a/lib/api/entities/feature_flag.rb
+++ b/lib/api/entities/feature_flag.rb
@@ -9,7 +9,9 @@ module API
expose :version
expose :created_at
expose :updated_at
- expose :scopes, using: FeatureFlag::LegacyScope
+ expose :scopes do |_ff|
+ []
+ end
expose :strategies, using: FeatureFlag::Strategy
end
end
diff --git a/lib/api/entities/feature_flag/detailed_legacy_scope.rb b/lib/api/entities/feature_flag/detailed_legacy_scope.rb
deleted file mode 100644
index 47078c1dfde..00000000000
--- a/lib/api/entities/feature_flag/detailed_legacy_scope.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-module API
- module Entities
- class FeatureFlag < Grape::Entity
- class DetailedLegacyScope < LegacyScope
- expose :name
- end
- end
- end
-end
diff --git a/lib/api/entities/feature_flag/legacy_scope.rb b/lib/api/entities/feature_flag/legacy_scope.rb
deleted file mode 100644
index 7329f71c599..00000000000
--- a/lib/api/entities/feature_flag/legacy_scope.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-module API
- module Entities
- class FeatureFlag < Grape::Entity
- class LegacyScope < Grape::Entity
- expose :id
- expose :active
- expose :environment_scope
- expose :strategies
- expose :created_at
- expose :updated_at
- end
- end
- end
-end
diff --git a/lib/banzai/filter/front_matter_filter.rb b/lib/banzai/filter/front_matter_filter.rb
index 5900e762244..d47900b816a 100644
--- a/lib/banzai/filter/front_matter_filter.rb
+++ b/lib/banzai/filter/front_matter_filter.rb
@@ -9,7 +9,7 @@ module Banzai
html.sub(Gitlab::FrontMatter::PATTERN) do |_match|
lang = $~[:lang].presence || lang_mapping[$~[:delim]]
- ["```#{lang}", $~[:front_matter], "```", "\n"].join("\n")
+ ["```#{lang}:frontmatter", $~[:front_matter], "```", "\n"].join("\n")
end
end
end
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index f1440c13d47..8d869cd63d3 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -28,6 +28,7 @@ module Banzai
def highlight_node(node)
css_classes = +'code highlight js-syntax-highlight'
lang, lang_params = parse_lang_params(node.attr('lang'))
+ sourcepos = node.parent.attr('data-sourcepos')
retried = false
if use_rouge?(lang)
@@ -55,7 +56,9 @@ module Banzai
retry
end
- highlighted = %(<pre class="#{css_classes}"
+ sourcepos_attr = sourcepos ? "data-sourcepos=\"#{sourcepos}\"" : ""
+
+ highlighted = %(<pre #{sourcepos_attr} class="#{css_classes}"
lang="#{language}"
#{lang_params}
v-pre="true"><code>#{code}</code></pre>)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index d95a5fa2aca..89630cdbf34 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4276,6 +4276,9 @@ msgstr ""
msgid "ApprovalSettings|This setting is configured at the instance level and can only be changed by an administrator."
msgstr ""
+msgid "ApprovalSettings|This setting is configured in %{groupName} and can only be changed by an administrator or group owner."
+msgstr ""
+
msgid "ApprovalStatusTooltip|Adheres to separation of duties"
msgstr ""
@@ -6546,6 +6549,9 @@ msgstr ""
msgid "Checkout"
msgstr ""
+msgid "Checkout|$%{selectedPlanPrice} per 10 GB storage per pack"
+msgstr ""
+
msgid "Checkout|$%{selectedPlanPrice} per pack of 1,000 minutes"
msgstr ""
@@ -6566,6 +6572,9 @@ msgstr ""
msgid "Checkout|%{name}'s GitLab subscription"
msgstr ""
+msgid "Checkout|%{name}'s storage subscription"
+msgstr ""
+
msgid "Checkout|%{quantity} GB of storage"
msgstr ""
@@ -6730,6 +6739,9 @@ msgstr ""
msgid "Checkout|Your organization"
msgstr ""
+msgid "Checkout|Your storage subscription has the same term as your main subscription, and the price is prorated accordingly."
+msgstr ""
+
msgid "Checkout|Your subscription will be applied to this group"
msgstr ""
@@ -16672,6 +16684,21 @@ msgstr ""
msgid "Hello, %{username}!"
msgstr ""
+msgid "HelloMessage|%{handshake_emoji} Contribute to GitLab: %{contribute_link}"
+msgstr ""
+
+msgid "HelloMessage|%{magnifier_emoji} Create a new GitLab issue: %{new_issue_link}"
+msgstr ""
+
+msgid "HelloMessage|%{rocket_emoji} We like your curiosity! Help us improve GitLab by joining the team: %{jobs_page_link}"
+msgstr ""
+
+msgid "HelloMessage|Does this page need fixes or improvements? Open an issue or contribute a merge request to help make GitLab more lovable. At GitLab, everyone can contribute!"
+msgstr ""
+
+msgid "HelloMessage|Welcome to GitLab!"
+msgstr ""
+
msgid "Help"
msgstr ""
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
index cfa9b900448..7519f4daae2 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
@@ -38,11 +38,7 @@ module QA
end
end
- context 'when using attachments in comments', :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209#note_681513082',
- type: :investigating
- } do
+ context 'when using attachments in comments', :object_storage do
let(:png_file_name) { 'testfile.png' }
let(:file_to_attach) do
File.absolute_path(File.join('qa', 'fixtures', 'designs', png_file_name))
diff --git a/qa/qa/specs/features/browser_ui/5_package/composer_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/composer_registry_spec.rb
index bb9563acc90..9ddf485870d 100644
--- a/qa/qa/specs/features/browser_ui/5_package/composer_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/composer_registry_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209#note_681513082',
- type: :investigating
- } do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
describe 'Composer Repository' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/generic_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/generic_repository_spec.rb
index f8ca3f5af3e..2e5fa2c2904 100644
--- a/qa/qa/specs/features/browser_ui/5_package/generic_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/generic_repository_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209#note_681513082',
- type: :investigating
- } do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
describe 'Generic Repository' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/5_package/helm_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/helm_registry_spec.rb
index 96d1eb30268..fe52fd03ad8 100644
--- a/qa/qa/specs/features/browser_ui/5_package/helm_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/helm_registry_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209',
- type: :investigating
- } do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
describe 'Helm Registry' do
include Runtime::Fixtures
include_context 'packages registry qa scenario'
diff --git a/qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb
index d879e3a70c4..ec9feca84b9 100644
--- a/qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/maven_gradle_repository_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209#note_681513082',
- type: :investigating
- } do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
describe 'Maven Repository with Gradle' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb
index ea55a07db15..bf1d2a04dba 100644
--- a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :reliable, :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209#note_681513082',
- type: :investigating
- } do
+ RSpec.describe 'Package', :orchestrated, :packages, :reliable, :object_storage do
describe 'Maven Repository' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb
index 19c194cf5ac..5a3b4388f0c 100644
--- a/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :reliable, :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209#note_681513082',
- type: :investigating
- } do
+ RSpec.describe 'Package', :orchestrated, :packages, :reliable, :object_storage do
describe 'npm registry' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb
index 5813e7358d4..8a6752ed817 100644
--- a/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209#note_681513082',
- type: :investigating
- } do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
describe 'NuGet Repository' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb
index 74407e112a1..dfc9202ebed 100644
--- a/qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209#note_681513082',
- type: :investigating
- } do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
describe 'PyPI Repository' do
include Runtime::Fixtures
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/5_package/rubygems_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/rubygems_registry_spec.rb
index 0d22b3bbbff..9a45b072eed 100644
--- a/qa/qa/specs/features/browser_ui/5_package/rubygems_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/rubygems_registry_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :requires_admin, :packages, :object_storage, quarantine: {
- only: { job: 'object_storage' },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209#note_681513082',
- type: :investigating
- } do
+ RSpec.describe 'Package', :orchestrated, :requires_admin, :packages, :object_storage do
describe 'RubyGems Repository' do
include Runtime::Fixtures
diff --git a/spec/factories/namespaces/user_namespaces.rb b/spec/factories/namespaces/user_namespaces.rb
new file mode 100644
index 00000000000..31c924462d7
--- /dev/null
+++ b/spec/factories/namespaces/user_namespaces.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :user_namespace, class: 'Namespaces::UserNamespace', parent: :namespace do
+ sequence(:name) { |n| "user_namespace#{n}" }
+ type { Namespaces::UserNamespace.sti_name }
+ end
+end
diff --git a/spec/frontend/ide/components/jobs/detail_spec.js b/spec/frontend/ide/components/jobs/detail_spec.js
index 79ac0a8122a..3634599f328 100644
--- a/spec/frontend/ide/components/jobs/detail_spec.js
+++ b/spec/frontend/ide/components/jobs/detail_spec.js
@@ -41,7 +41,7 @@ describe('IDE jobs detail view', () => {
});
it('scrolls to bottom', () => {
- expect(vm.$refs.buildTrace.scrollTo).toHaveBeenCalled();
+ expect(vm.$refs.buildJobLog.scrollTo).toHaveBeenCalled();
});
it('renders job output', () => {
@@ -125,15 +125,15 @@ describe('IDE jobs detail view', () => {
beforeEach(() => {
vm = vm.$mount();
- jest.spyOn(vm.$refs.buildTrace, 'scrollTo').mockImplementation();
+ jest.spyOn(vm.$refs.buildJobLog, 'scrollTo').mockImplementation();
});
it('scrolls build trace to bottom', () => {
- jest.spyOn(vm.$refs.buildTrace, 'scrollHeight', 'get').mockReturnValue(1000);
+ jest.spyOn(vm.$refs.buildJobLog, 'scrollHeight', 'get').mockReturnValue(1000);
vm.scrollDown();
- expect(vm.$refs.buildTrace.scrollTo).toHaveBeenCalledWith(0, 1000);
+ expect(vm.$refs.buildJobLog.scrollTo).toHaveBeenCalledWith(0, 1000);
});
});
@@ -141,26 +141,26 @@ describe('IDE jobs detail view', () => {
beforeEach(() => {
vm = vm.$mount();
- jest.spyOn(vm.$refs.buildTrace, 'scrollTo').mockImplementation();
+ jest.spyOn(vm.$refs.buildJobLog, 'scrollTo').mockImplementation();
});
it('scrolls build trace to top', () => {
vm.scrollUp();
- expect(vm.$refs.buildTrace.scrollTo).toHaveBeenCalledWith(0, 0);
+ expect(vm.$refs.buildJobLog.scrollTo).toHaveBeenCalledWith(0, 0);
});
});
describe('scrollBuildLog', () => {
beforeEach(() => {
vm = vm.$mount();
- jest.spyOn(vm.$refs.buildTrace, 'scrollTo').mockImplementation();
- jest.spyOn(vm.$refs.buildTrace, 'offsetHeight', 'get').mockReturnValue(100);
- jest.spyOn(vm.$refs.buildTrace, 'scrollHeight', 'get').mockReturnValue(200);
+ jest.spyOn(vm.$refs.buildJobLog, 'scrollTo').mockImplementation();
+ jest.spyOn(vm.$refs.buildJobLog, 'offsetHeight', 'get').mockReturnValue(100);
+ jest.spyOn(vm.$refs.buildJobLog, 'scrollHeight', 'get').mockReturnValue(200);
});
it('sets scrollPos to bottom when at the bottom', () => {
- jest.spyOn(vm.$refs.buildTrace, 'scrollTop', 'get').mockReturnValue(100);
+ jest.spyOn(vm.$refs.buildJobLog, 'scrollTop', 'get').mockReturnValue(100);
vm.scrollBuildLog();
@@ -168,7 +168,7 @@ describe('IDE jobs detail view', () => {
});
it('sets scrollPos to top when at the top', () => {
- jest.spyOn(vm.$refs.buildTrace, 'scrollTop', 'get').mockReturnValue(0);
+ jest.spyOn(vm.$refs.buildJobLog, 'scrollTop', 'get').mockReturnValue(0);
vm.scrollPos = 1;
vm.scrollBuildLog();
@@ -177,7 +177,7 @@ describe('IDE jobs detail view', () => {
});
it('resets scrollPos when not at top or bottom', () => {
- jest.spyOn(vm.$refs.buildTrace, 'scrollTop', 'get').mockReturnValue(10);
+ jest.spyOn(vm.$refs.buildJobLog, 'scrollTop', 'get').mockReturnValue(10);
vm.scrollBuildLog();
diff --git a/spec/frontend/lib/logger/__snapshots__/hello_spec.js.snap b/spec/frontend/lib/logger/__snapshots__/hello_spec.js.snap
index 791ec05befd..0b156049dab 100644
--- a/spec/frontend/lib/logger/__snapshots__/hello_spec.js.snap
+++ b/spec/frontend/lib/logger/__snapshots__/hello_spec.js.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`~/lib/logger/hello logHello console logs a friendly hello message 1`] = `
+exports[`~/lib/logger/hello logHello when on dot_com console logs a friendly hello message including the careers page 1`] = `
Array [
Array [
"%cWelcome to GitLab!%c
@@ -8,7 +8,24 @@ Array [
Does this page need fixes or improvements? Open an issue or contribute a merge request to help make GitLab more lovable. At GitLab, everyone can contribute!
🤝 Contribute to GitLab: https://about.gitlab.com/community/contribute/
-🔎 Create a new GitLab issue: https://gitlab.com/gitlab-org/gitlab/-/issues/new",
+🔎 Create a new GitLab issue: https://gitlab.com/gitlab-org/gitlab/-/issues/new
+🚀 We like your curiosity! Help us improve GitLab by joining the team: https://about.gitlab.com/jobs/",
+ "padding-top: 0.5em; font-size: 2em;",
+ "padding-bottom: 0.5em;",
+ ],
+]
+`;
+
+exports[`~/lib/logger/hello logHello when on self managed console logs a friendly hello message without including the careers page 1`] = `
+Array [
+ Array [
+ "%cWelcome to GitLab!%c
+
+Does this page need fixes or improvements? Open an issue or contribute a merge request to help make GitLab more lovable. At GitLab, everyone can contribute!
+
+🤝 Contribute to GitLab: https://about.gitlab.com/community/contribute/
+🔎 Create a new GitLab issue: https://gitlab.com/gitlab-org/gitlab/-/issues/new
+",
"padding-top: 0.5em; font-size: 2em;",
"padding-bottom: 0.5em;",
],
diff --git a/spec/frontend/lib/logger/hello_spec.js b/spec/frontend/lib/logger/hello_spec.js
index 39abe0e0dd0..39c1b55313b 100644
--- a/spec/frontend/lib/logger/hello_spec.js
+++ b/spec/frontend/lib/logger/hello_spec.js
@@ -9,12 +9,32 @@ describe('~/lib/logger/hello', () => {
});
describe('logHello', () => {
- it('console logs a friendly hello message', () => {
- expect(consoleLogSpy).not.toHaveBeenCalled();
+ describe('when on dot_com', () => {
+ beforeEach(() => {
+ gon.dot_com = true;
+ });
- logHello();
+ it('console logs a friendly hello message including the careers page', () => {
+ expect(consoleLogSpy).not.toHaveBeenCalled();
- expect(consoleLogSpy.mock.calls).toMatchSnapshot();
+ logHello();
+
+ expect(consoleLogSpy.mock.calls).toMatchSnapshot();
+ });
+ });
+
+ describe('when on self managed', () => {
+ beforeEach(() => {
+ gon.dot_com = false;
+ });
+
+ it('console logs a friendly hello message without including the careers page', () => {
+ expect(consoleLogSpy).not.toHaveBeenCalled();
+
+ logHello();
+
+ expect(consoleLogSpy.mock.calls).toMatchSnapshot();
+ });
});
});
});
diff --git a/spec/initializers/carrierwave_patch_spec.rb b/spec/initializers/carrierwave_patch_spec.rb
index cbdad4aa9ac..e219db2299d 100644
--- a/spec/initializers/carrierwave_patch_spec.rb
+++ b/spec/initializers/carrierwave_patch_spec.rb
@@ -81,19 +81,32 @@ RSpec.describe 'CarrierWave::Storage::Fog::File' do
end
describe '#authenticated_url' do
+ let(:expire_at) { 24.hours.from_now }
+ let(:options) { { expire_at: expire_at } }
+
it 'has an authenticated URL' do
- expect(subject.authenticated_url).to eq("https://sa.blob.core.windows.net/test_container/test_blob?token")
+ expect(subject.authenticated_url(options)).to eq("https://sa.blob.core.windows.net/test_container/test_blob?token")
end
context 'with custom expire_at' do
it 'properly sets expires param' do
- expire_at = 24.hours.from_now
+ expect_next_instance_of(Fog::Storage::AzureRM::File) do |file|
+ expect(file).to receive(:url).with(expire_at, options).and_call_original
+ end
+
+ expect(subject.authenticated_url(options)).to eq("https://sa.blob.core.windows.net/test_container/test_blob?token")
+ end
+ end
+
+ context 'with content_disposition option' do
+ let(:options) { { expire_at: expire_at, content_disposition: 'attachment' } }
+ it 'passes options' do
expect_next_instance_of(Fog::Storage::AzureRM::File) do |file|
- expect(file).to receive(:url).with(expire_at).and_call_original
+ expect(file).to receive(:url).with(expire_at, options).and_call_original
end
- expect(subject.authenticated_url(expire_at: expire_at)).to eq("https://sa.blob.core.windows.net/test_container/test_blob?token")
+ expect(subject.authenticated_url(options)).to eq("https://sa.blob.core.windows.net/test_container/test_blob?token")
end
end
end
diff --git a/spec/lib/banzai/filter/front_matter_filter_spec.rb b/spec/lib/banzai/filter/front_matter_filter_spec.rb
index 3f966c94dd3..cef6a2ddcce 100644
--- a/spec/lib/banzai/filter/front_matter_filter_spec.rb
+++ b/spec/lib/banzai/filter/front_matter_filter_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe Banzai::Filter::FrontMatterFilter do
aggregate_failures do
expect(output).not_to include '---'
- expect(output).to include "```yaml\nfoo: :foo_symbol\n"
+ expect(output).to include "```yaml:frontmatter\nfoo: :foo_symbol\n"
end
end
@@ -59,7 +59,7 @@ RSpec.describe Banzai::Filter::FrontMatterFilter do
aggregate_failures do
expect(output).not_to include '+++'
- expect(output).to include "```toml\nfoo = :foo_symbol\n"
+ expect(output).to include "```toml:frontmatter\nfoo = :foo_symbol\n"
end
end
@@ -81,7 +81,7 @@ RSpec.describe Banzai::Filter::FrontMatterFilter do
aggregate_failures do
expect(output).not_to include ';;;'
- expect(output).to include "```json\n{\n \"foo\": \":foo_symbol\",\n"
+ expect(output).to include "```json:frontmatter\n{\n \"foo\": \":foo_symbol\",\n"
end
end
@@ -101,7 +101,7 @@ RSpec.describe Banzai::Filter::FrontMatterFilter do
aggregate_failures do
expect(output).not_to include '---arbitrary'
- expect(output).to include "```arbitrary\nfoo = :foo_symbol\n"
+ expect(output).to include "```arbitrary:frontmatter\nfoo = :foo_symbol\n"
end
end
@@ -130,7 +130,7 @@ RSpec.describe Banzai::Filter::FrontMatterFilter do
aggregate_failures do
expect(output).to eq <<~MD
- ```yaml
+ ```yaml:frontmatter
foo: :foo_symbol
bar: :bar_symbol
```
diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
index 16e30604c99..7e45ecdd135 100644
--- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -98,6 +98,14 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
end
end
+ context "when sourcepos metadata is available" do
+ it "includes it in the highlighted code block" do
+ result = filter('<pre data-sourcepos="1:1-3:3"><code lang="plaintext">This is a test</code></pre>')
+
+ expect(result.to_html).to eq('<pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre>')
+ end
+ end
+
context "when Rouge lexing fails" do
before do
allow_next_instance_of(Rouge::Lexers::Ruby) do |instance|
diff --git a/spec/lib/banzai/pipeline/pre_process_pipeline_spec.rb b/spec/lib/banzai/pipeline/pre_process_pipeline_spec.rb
index c628d8d5b41..5021ef3a79a 100644
--- a/spec/lib/banzai/pipeline/pre_process_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/pre_process_pipeline_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Banzai::Pipeline::PreProcessPipeline do
aggregate_failures do
expect(result[:output]).not_to include "\xEF\xBB\xBF"
expect(result[:output]).not_to include '---'
- expect(result[:output]).to include "```yaml\nfoo: :foo_symbol\n"
+ expect(result[:output]).to include "```yaml:frontmatter\nfoo: :foo_symbol\n"
expect(result[:output]).to include "> blockquote\n"
end
end
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index 7dabc4af645..1dfd5084954 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -73,21 +73,61 @@ RSpec.describe Ci::Bridge do
describe 'state machine transitions' do
context 'when bridge points towards downstream' do
%i[created manual].each do |status|
- it "schedules downstream pipeline creation when the status is #{status}" do
- bridge.status = status
+ context 'when the create_cross_project_pipeline_worker_rename feature is enabled' do
+ before do
+ stub_feature_flags(create_cross_project_pipeline_worker_rename: true)
+ end
- bridge.enqueue!
+ it "schedules downstream pipeline creation when the status is #{status}" do
+ bridge.status = status
- expect(::Ci::CreateCrossProjectPipelineWorker.jobs.last['args']).to eq([bridge.id])
+ bridge.enqueue!
+
+ expect(::Ci::CreateDownstreamPipelineWorker.jobs.last['args']).to eq([bridge.id])
+ end
+ end
+
+ context 'when the create_cross_project_pipeline_worker_rename feature is not enabled' do
+ before do
+ stub_feature_flags(create_cross_project_pipeline_worker_rename: false)
+ end
+
+ it "schedules downstream pipeline creation when the status is #{status}" do
+ bridge.status = status
+
+ bridge.enqueue!
+
+ expect(::Ci::CreateCrossProjectPipelineWorker.jobs.last['args']).to eq([bridge.id])
+ end
end
end
- it "schedules downstream pipeline creation when the status is waiting for resource" do
- bridge.status = :waiting_for_resource
+ context 'when the create_cross_project_pipeline_worker_rename feature is enabled' do
+ before do
+ stub_feature_flags(create_cross_project_pipeline_worker_rename: true)
+ end
+
+ it "schedules downstream pipeline creation when the status is waiting for resource" do
+ bridge.status = :waiting_for_resource
+
+ bridge.enqueue_waiting_for_resource!
- bridge.enqueue_waiting_for_resource!
+ expect(::Ci::CreateDownstreamPipelineWorker.jobs.last['args']).to eq([bridge.id])
+ end
+ end
- expect(::Ci::CreateCrossProjectPipelineWorker.jobs.last['args']).to eq([bridge.id])
+ context 'when the create_cross_project_pipeline_worker_rename feature is not enabled' do
+ before do
+ stub_feature_flags(create_cross_project_pipeline_worker_rename: false)
+ end
+
+ it "schedules downstream pipeline creation when the status is waiting for resource" do
+ bridge.status = :waiting_for_resource
+
+ bridge.enqueue_waiting_for_resource!
+
+ expect(::Ci::CreateCrossProjectPipelineWorker.jobs.last['args']).to eq([bridge.id])
+ end
end
it 'raises error when the status is failed' do
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index a1c2444ee27..8864994c15f 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -178,7 +178,7 @@ RSpec.describe Namespace do
context 'creating a Group' do
let(:namespace_type) { group_sti_name }
- it 'is valid' do
+ it 'is the correct type of namespace' do
expect(namespace).to be_a(Group)
expect(namespace.kind).to eq('group')
expect(namespace.group_namespace?).to be_truthy
@@ -189,7 +189,7 @@ RSpec.describe Namespace do
let(:namespace_type) { project_sti_name }
let(:parent) { create(:group) }
- it 'is valid' do
+ it 'is the correct type of namespace' do
expect(Namespace.find(namespace.id)).to be_a(Namespaces::ProjectNamespace)
expect(namespace.kind).to eq('project')
expect(namespace.project_namespace?).to be_truthy
@@ -199,10 +199,8 @@ RSpec.describe Namespace do
context 'creating a UserNamespace' do
let(:namespace_type) { user_sti_name }
- it 'is valid' do
- # TODO: We create a normal Namespace until
- # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68894 is ready
- expect(Namespace.find(namespace.id)).to be_a(Namespace)
+ it 'is the correct type of namespace' do
+ expect(Namespace.find(namespace.id)).to be_a(Namespaces::UserNamespace)
expect(namespace.kind).to eq('user')
expect(namespace.user_namespace?).to be_truthy
end
@@ -211,7 +209,7 @@ RSpec.describe Namespace do
context 'creating a default Namespace' do
let(:namespace_type) { nil }
- it 'is valid' do
+ it 'is the correct type of namespace' do
expect(Namespace.find(namespace.id)).to be_a(Namespace)
expect(namespace.kind).to eq('user')
expect(namespace.user_namespace?).to be_truthy
@@ -221,7 +219,7 @@ RSpec.describe Namespace do
context 'creating an unknown Namespace type' do
let(:namespace_type) { 'One' }
- it 'defaults to a Namespace' do
+ it 'creates a default Namespace' do
expect(Namespace.find(namespace.id)).to be_a(Namespace)
expect(namespace.kind).to eq('user')
expect(namespace.user_namespace?).to be_truthy
diff --git a/spec/models/namespaces/user_namespace_spec.rb b/spec/models/namespaces/user_namespace_spec.rb
new file mode 100644
index 00000000000..7c00a597756
--- /dev/null
+++ b/spec/models/namespaces/user_namespace_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+# Main user namespace functionality it still in `Namespace`, so most
+# of the specs are in `namespace_spec.rb`.
+# UserNamespace specific specs will end up being migrated here.
+RSpec.describe Namespaces::UserNamespace, type: :model do
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:owner) }
+ end
+end
diff --git a/spec/models/operations/feature_flag_spec.rb b/spec/models/operations/feature_flag_spec.rb
index d689632e2b4..aabe5b70ade 100644
--- a/spec/models/operations/feature_flag_spec.rb
+++ b/spec/models/operations/feature_flag_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Operations::FeatureFlag do
describe 'associations' do
it { is_expected.to belong_to(:project) }
- it { is_expected.to have_many(:scopes) }
+ it { is_expected.to have_many(:strategies) }
end
describe '.reference_pattern' do
@@ -52,17 +52,6 @@ RSpec.describe Operations::FeatureFlag do
it { is_expected.to define_enum_for(:version).with_values(new_version_flag: 2) }
context 'a version 2 feature flag' do
- it 'is invalid if associated with Operations::FeatureFlagScope models' do
- project = create(:project)
- feature_flag = described_class.new({ name: 'test', project: project, version: 2,
- scopes_attributes: [{ environment_scope: '*', active: false }] })
-
- expect(feature_flag.valid?).to eq(false)
- expect(feature_flag.errors.messages).to eq({
- version_associations: ["version 2 feature flags may not have scopes"]
- })
- end
-
it 'is valid if associated with Operations::FeatureFlags::Strategy models' do
project = create(:project)
feature_flag = described_class.create!({ name: 'test', project: project, version: 2,
@@ -81,18 +70,6 @@ RSpec.describe Operations::FeatureFlag do
end
end
- describe 'the default scope' do
- let_it_be(:project) { create(:project) }
-
- context 'with a version 2 feature flag' do
- it 'does not create a default scope' do
- feature_flag = described_class.create!({ name: 'test', project: project, scopes_attributes: [], version: 2 })
-
- expect(feature_flag.scopes).to eq([])
- end
- end
- end
-
describe '.enabled' do
subject { described_class.enabled }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 334f9b4ae30..4cbd702cb8a 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2542,71 +2542,79 @@ RSpec.describe User do
end
describe '.find_by_full_path' do
- let!(:user) { create(:user) }
+ using RSpec::Parameterized::TableSyntax
- context 'with a route matching the given path' do
- let!(:route) { user.namespace.route }
+ # TODO: this `where/when` can be removed in issue https://gitlab.com/gitlab-org/gitlab/-/issues/341070
+ # At that point we only need to check `user_namespace`
+ where(namespace_type: [:namespace, :user_namespace])
- it 'returns the user' do
- expect(described_class.find_by_full_path(route.path)).to eq(user)
- end
+ with_them do
+ let!(:user) { create(:user, namespace: create(namespace_type)) }
- it 'is case-insensitive' do
- expect(described_class.find_by_full_path(route.path.upcase)).to eq(user)
- expect(described_class.find_by_full_path(route.path.downcase)).to eq(user)
- end
- end
+ context 'with a route matching the given path' do
+ let!(:route) { user.namespace.route }
- context 'with a redirect route matching the given path' do
- let!(:redirect_route) { user.namespace.redirect_routes.create!(path: 'foo') }
+ it 'returns the user' do
+ expect(described_class.find_by_full_path(route.path)).to eq(user)
+ end
- context 'without the follow_redirects option' do
- it 'returns nil' do
- expect(described_class.find_by_full_path(redirect_route.path)).to eq(nil)
+ it 'is case-insensitive' do
+ expect(described_class.find_by_full_path(route.path.upcase)).to eq(user)
+ expect(described_class.find_by_full_path(route.path.downcase)).to eq(user)
end
end
- context 'with the follow_redirects option set to true' do
- it 'returns the user' do
- expect(described_class.find_by_full_path(redirect_route.path, follow_redirects: true)).to eq(user)
+ context 'with a redirect route matching the given path' do
+ let!(:redirect_route) { user.namespace.redirect_routes.create!(path: 'foo') }
+
+ context 'without the follow_redirects option' do
+ it 'returns nil' do
+ expect(described_class.find_by_full_path(redirect_route.path)).to eq(nil)
+ end
end
- it 'is case-insensitive' do
- expect(described_class.find_by_full_path(redirect_route.path.upcase, follow_redirects: true)).to eq(user)
- expect(described_class.find_by_full_path(redirect_route.path.downcase, follow_redirects: true)).to eq(user)
+ context 'with the follow_redirects option set to true' do
+ it 'returns the user' do
+ expect(described_class.find_by_full_path(redirect_route.path, follow_redirects: true)).to eq(user)
+ end
+
+ it 'is case-insensitive' do
+ expect(described_class.find_by_full_path(redirect_route.path.upcase, follow_redirects: true)).to eq(user)
+ expect(described_class.find_by_full_path(redirect_route.path.downcase, follow_redirects: true)).to eq(user)
+ end
end
end
- end
- context 'without a route or a redirect route matching the given path' do
- context 'without the follow_redirects option' do
- it 'returns nil' do
- expect(described_class.find_by_full_path('unknown')).to eq(nil)
+ context 'without a route or a redirect route matching the given path' do
+ context 'without the follow_redirects option' do
+ it 'returns nil' do
+ expect(described_class.find_by_full_path('unknown')).to eq(nil)
+ end
end
- end
- context 'with the follow_redirects option set to true' do
- it 'returns nil' do
- expect(described_class.find_by_full_path('unknown', follow_redirects: true)).to eq(nil)
+ context 'with the follow_redirects option set to true' do
+ it 'returns nil' do
+ expect(described_class.find_by_full_path('unknown', follow_redirects: true)).to eq(nil)
+ end
end
end
- end
- context 'with a group route matching the given path' do
- let!(:group) { create(:group, path: 'group_path') }
+ context 'with a group route matching the given path' do
+ let!(:group) { create(:group, path: 'group_path') }
- context 'when the group namespace has an owner_id (legacy data)' do
- before do
- group.update!(owner_id: user.id)
- end
+ context 'when the group namespace has an owner_id (legacy data)' do
+ before do
+ group.update!(owner_id: user.id)
+ end
- it 'returns nil' do
- expect(described_class.find_by_full_path('group_path')).to eq(nil)
+ it 'returns nil' do
+ expect(described_class.find_by_full_path('group_path')).to eq(nil)
+ end
end
- end
- context 'when the group namespace does not have an owner_id' do
- it 'returns nil' do
- expect(described_class.find_by_full_path('group_path')).to eq(nil)
+ context 'when the group namespace does not have an owner_id' do
+ it 'returns nil' do
+ expect(described_class.find_by_full_path('group_path')).to eq(nil)
+ end
end
end
end
diff --git a/spec/services/ci/play_bridge_service_spec.rb b/spec/services/ci/play_bridge_service_spec.rb
index 3f97bfdf5ae..665f25de299 100644
--- a/spec/services/ci/play_bridge_service_spec.rb
+++ b/spec/services/ci/play_bridge_service_spec.rb
@@ -23,18 +23,36 @@ RSpec.describe Ci::PlayBridgeService, '#execute' do
expect(bridge.reload).to be_pending
end
- it 'enqueues Ci::CreateCrossProjectPipelineWorker' do
- expect(::Ci::CreateCrossProjectPipelineWorker).to receive(:perform_async).with(bridge.id)
-
- execute_service
- end
-
it "updates bridge's user" do
execute_service
expect(bridge.reload.user).to eq(user)
end
+ context 'when the create_cross_project_pipeline_worker_rename feature is enabled' do
+ before do
+ stub_feature_flags(create_cross_project_pipeline_worker_rename: true)
+ end
+
+ it 'enqueues Ci::CreateDownstreamPipelineWorker' do
+ expect(::Ci::CreateDownstreamPipelineWorker).to receive(:perform_async).with(bridge.id)
+
+ execute_service
+ end
+ end
+
+ context 'when the create_cross_project_pipeline_worker_rename feature is not enabled' do
+ before do
+ stub_feature_flags(create_cross_project_pipeline_worker_rename: false)
+ end
+
+ it 'enqueues Ci::CreateCrossProjectPipelineWorker' do
+ expect(::Ci::CreateCrossProjectPipelineWorker).to receive(:perform_async).with(bridge.id)
+
+ execute_service
+ end
+ end
+
context 'when a subsequent job is skipped' do
let!(:job) { create(:ci_build, :skipped, pipeline: pipeline, stage_idx: bridge.stage_idx + 1) }
diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb
index c7715eb43fc..8a73c484403 100644
--- a/spec/tooling/danger/project_helper_spec.rb
+++ b/spec/tooling/danger/project_helper_spec.rb
@@ -93,6 +93,9 @@ RSpec.describe Tooling::Danger::ProjectHelper do
'ee/spec/foo' | [:backend]
'ee/spec/foo/bar' | [:backend]
+ 'spec/migrations/foo' | [:database]
+ 'ee/spec/migrations/foo' | [:database]
+
'spec/features/foo' | [:test]
'ee/spec/features/foo' | [:test]
'spec/support/shared_examples/features/foo' | [:test]
diff --git a/spec/workers/ci/create_downstream_pipeline_worker_spec.rb b/spec/workers/ci/create_downstream_pipeline_worker_spec.rb
new file mode 100644
index 00000000000..7a75da850d9
--- /dev/null
+++ b/spec/workers/ci/create_downstream_pipeline_worker_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::CreateDownstreamPipelineWorker do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+
+ let(:bridge) { create(:ci_bridge, user: user, pipeline: pipeline) }
+
+ let(:service) { double('pipeline creation service') }
+
+ describe '#perform' do
+ context 'when bridge exists' do
+ it 'calls cross project pipeline creation service' do
+ expect(Ci::CreateDownstreamPipelineService)
+ .to receive(:new)
+ .with(project, user)
+ .and_return(service)
+
+ expect(service).to receive(:execute).with(bridge)
+
+ described_class.new.perform(bridge.id)
+ end
+ end
+
+ context 'when bridge does not exist' do
+ it 'does nothing' do
+ expect(Ci::CreateDownstreamPipelineService)
+ .not_to receive(:new)
+
+ described_class.new.perform(non_existing_record_id)
+ end
+ end
+ end
+end
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index 235a1f6e3dd..c68c38653bf 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -155,6 +155,7 @@ RSpec.describe 'Every Sidekiq worker' do
'Ci::BuildScheduleWorker' => 3,
'Ci::BuildTraceChunkFlushWorker' => 3,
'Ci::CreateCrossProjectPipelineWorker' => 3,
+ 'Ci::CreateDownstreamPipelineWorker' => 3,
'Ci::DailyBuildGroupReportResultsWorker' => 3,
'Ci::DeleteObjectsWorker' => 0,
'Ci::DropPipelineWorker' => 3,
diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb
index 109f77ed4d1..eb2a47e1f8a 100644
--- a/tooling/danger/project_helper.rb
+++ b/tooling/danger/project_helper.rb
@@ -113,6 +113,7 @@ module Tooling
generator_templates/usage_metric_definition/metric_definition\.yml)\z}x => [:backend, :product_intelligence],
%r{\A((ee|jh)/)?app/(?!assets|views)[^/]+} => :backend,
%r{\A((ee|jh)/)?(bin|config|generator_templates|lib|rubocop)/} => :backend,
+ %r{\A((ee|jh)/)?spec/migrations} => :database,
%r{\A((ee|jh)/)?spec/} => :backend,
%r{\A((ee|jh)/)?vendor/} => :backend,
%r{\A(Gemfile|Gemfile.lock|Rakefile)\z} => :backend,