From 8c4e384860c39494c3436b7d6f3567458f79f0d9 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 23 Sep 2021 12:11:29 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- GITLAB_SHELL_VERSION | 2 +- Gemfile | 2 +- Gemfile.lock | 4 +- .../javascripts/ide/components/jobs/detail.vue | 14 +-- app/assets/javascripts/lib/logger/hello.js | 29 ++++- app/helpers/ci/jobs_helper.rb | 2 +- app/models/ci/bridge.rb | 6 +- app/models/namespace.rb | 8 +- app/models/namespaces/user_namespace.rb | 2 +- app/models/operations/feature_flag.rb | 30 +---- app/models/operations/feature_flag_scope.rb | 66 ----------- app/models/user.rb | 6 +- app/serializers/feature_flag_entity.rb | 4 +- app/serializers/feature_flag_scope_entity.rb | 12 -- app/workers/all_queues.yml | 9 ++ .../ci/create_downstream_pipeline_worker.rb | 19 +++ ...create_cross_project_pipeline_worker_rename.yml | 8 ++ config/initializers/carrierwave_patch.rb | 10 +- doc/development/index.md | 1 + doc/development/redis.md | 5 + doc/development/redis/new_redis_instance.md | 131 +++++++++++++++++++++ .../end_to_end/rspec_metadata_tests.md | 1 + doc/user/admin_area/index.md | 8 +- lib/api/entities/feature_flag.rb | 4 +- .../entities/feature_flag/detailed_legacy_scope.rb | 11 -- lib/api/entities/feature_flag/legacy_scope.rb | 16 --- lib/banzai/filter/front_matter_filter.rb | 2 +- lib/banzai/filter/syntax_highlight_filter.rb | 5 +- locale/gitlab.pot | 27 +++++ .../browser_ui/2_plan/issue/create_issue_spec.rb | 6 +- .../browser_ui/5_package/composer_registry_spec.rb | 6 +- .../5_package/generic_repository_spec.rb | 6 +- .../browser_ui/5_package/helm_registry_spec.rb | 6 +- .../5_package/maven_gradle_repository_spec.rb | 6 +- .../browser_ui/5_package/maven_repository_spec.rb | 6 +- .../browser_ui/5_package/npm_registry_spec.rb | 6 +- .../browser_ui/5_package/nuget_repository_spec.rb | 6 +- .../browser_ui/5_package/pypi_repository_spec.rb | 6 +- .../browser_ui/5_package/rubygems_registry_spec.rb | 6 +- spec/factories/namespaces/user_namespaces.rb | 8 ++ spec/frontend/ide/components/jobs/detail_spec.js | 24 ++-- .../lib/logger/__snapshots__/hello_spec.js.snap | 21 +++- spec/frontend/lib/logger/hello_spec.js | 28 ++++- spec/initializers/carrierwave_patch_spec.rb | 21 +++- spec/lib/banzai/filter/front_matter_filter_spec.rb | 10 +- .../banzai/filter/syntax_highlight_filter_spec.rb | 8 ++ .../banzai/pipeline/pre_process_pipeline_spec.rb | 2 +- spec/models/ci/bridge_spec.rb | 56 +++++++-- spec/models/namespace_spec.rb | 14 +-- spec/models/namespaces/user_namespace_spec.rb | 12 ++ spec/models/operations/feature_flag_spec.rb | 25 +--- spec/models/user_spec.rb | 96 ++++++++------- spec/services/ci/play_bridge_service_spec.rb | 30 ++++- spec/tooling/danger/project_helper_spec.rb | 3 + .../ci/create_downstream_pipeline_worker_spec.rb | 37 ++++++ spec/workers/every_sidekiq_worker_spec.rb | 1 + tooling/danger/project_helper.rb | 1 + 57 files changed, 558 insertions(+), 343 deletions(-) delete mode 100644 app/models/operations/feature_flag_scope.rb delete mode 100644 app/serializers/feature_flag_scope_entity.rb create mode 100644 app/workers/ci/create_downstream_pipeline_worker.rb create mode 100644 config/feature_flags/development/create_cross_project_pipeline_worker_rename.yml create mode 100644 doc/development/redis/new_redis_instance.md delete mode 100644 lib/api/entities/feature_flag/detailed_legacy_scope.rb delete mode 100644 lib/api/entities/feature_flag/legacy_scope.rb create mode 100644 spec/factories/namespaces/user_namespaces.rb create mode 100644 spec/models/namespaces/user_namespace_spec.rb create mode 100644 spec/workers/ci/create_downstream_pipeline_worker_spec.rb 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 { -
+    
        {
   // 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
+
+
+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.
+
+
+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 = %(
#{code}
) 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('
This is a test
') + + expect(result.to_html).to eq('
This is a test
') + 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, -- cgit v1.2.3