From 4fd99b9a2a2f9c4463ff273e1e7e92d29a7bb306 Mon Sep 17 00:00:00 2001 From: Ashvin Sharma Date: Wed, 10 Sep 2025 11:07:10 +0530 Subject: [PATCH 1/3] Optimize workspace names Longer workspace names can have issues with Kubernetes since it only allows 63 characters in the name. PVCs and pod names have suffixes appended to the workspace name which can cause issues. As a result, workspace names are shortened. Changelog: other EE: true --- .../create/creator_bootstrapper.rb | 34 +---- .../create/workspace_name_generator.rb | 36 +++++ .../create/creator_bootstrapper_spec.rb | 85 ++---------- .../create/main_integration_spec.rb | 4 +- .../create/workspace_name_generator_spec.rb | 126 ++++++++++++++++++ .../remote_development/integration_spec.rb | 12 +- 6 files changed, 185 insertions(+), 112 deletions(-) create mode 100644 ee/lib/remote_development/workspace_operations/create/workspace_name_generator.rb create mode 100644 ee/spec/lib/remote_development/workspace_operations/create/workspace_name_generator_spec.rb diff --git a/ee/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb b/ee/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb index 46bfe152970a88..300760b249a85e 100644 --- a/ee/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb +++ b/ee/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb @@ -6,7 +6,7 @@ module Create class CreatorBootstrapper include CreateConstants - RANDOM_STRING_LENGTH = 6 + RANDOM_STRING_LENGTH = 5 # @param [Hash] context # @return [Hash] @@ -18,9 +18,7 @@ def self.bootstrap(context) } } - workspace_name_prefix = "workspace" - workspace_name_suffix = generate_unique_workspace_suffix(workspace_name_prefix) - workspace_name = "#{workspace_name_prefix}-#{workspace_name_suffix}" + workspace_name = WorkspaceNameGenerator.generate shared_namespace = agent.unversioned_latest_workspaces_agent_config.shared_namespace workspace_namespace = @@ -28,7 +26,7 @@ def self.bootstrap(context) case shared_namespace when "" # Use a unique namespace, with one workspace per namespace - "#{NAMESPACE_PREFIX}-#{workspace_name_suffix}" + "#{NAMESPACE_PREFIX}-#{workspace_name}" else # Use a shared namespace, with multiple workspaces in the same namespace shared_namespace @@ -39,32 +37,6 @@ def self.bootstrap(context) workspace_namespace: workspace_namespace ) end - - # @param [String] workspace_name_prefix - This is required to ensure uniqueness - # @return [String] - def self.generate_unique_workspace_suffix(workspace_name_prefix) - max_retries = 30 - - max_retries.times do |_| - workspace_name_suffix = [ - FFaker::Food.fruit, - FFaker::AnimalUS.common_name, - FFaker::Color.name - ].map(&:downcase) - .map(&:parameterize) - .join("-") - - workspace_name = [workspace_name_prefix, workspace_name_suffix].join("-") - - unless workspace_name.length > 64 || RemoteDevelopment::Workspace.by_names(workspace_name).exists? - return workspace_name_suffix - end - end - - raise "Unable to generate unique workspace name after #{max_retries} attempts" - end - - private_class_method :generate_unique_workspace_suffix end end end diff --git a/ee/lib/remote_development/workspace_operations/create/workspace_name_generator.rb b/ee/lib/remote_development/workspace_operations/create/workspace_name_generator.rb new file mode 100644 index 00000000000000..24ddfeed57b8e0 --- /dev/null +++ b/ee/lib/remote_development/workspace_operations/create/workspace_name_generator.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module RemoteDevelopment + module WorkspaceOperations + module Create + class WorkspaceNameGenerator + RANDOM_STRING_LENGTH = 5 + WORKSPACE_NAME_MAX_LENGTH = 34 + + # @return [String] + def self.generate + max_retries = 50 + workspace_name = "" + + max_retries.times do |_| + workspace_name = [ + FFaker::Food.fruit, + FFaker::AnimalUS.common_name, + FFaker::Color.name + ].map(&:downcase) + .map { |name| name.parameterize(separator: "") } + .join("-") + + unless workspace_name.length >= WORKSPACE_NAME_MAX_LENGTH || + RemoteDevelopment::Workspace.by_names(workspace_name).exists? + return workspace_name + end + end + + random_string = SecureRandom.alphanumeric(RANDOM_STRING_LENGTH).downcase + workspace_name[0..WORKSPACE_NAME_MAX_LENGTH - 1 - RANDOM_STRING_LENGTH] << random_string + end + end + end + end +end diff --git a/ee/spec/lib/remote_development/workspace_operations/create/creator_bootstrapper_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/creator_bootstrapper_spec.rb index eb60c8e335089a..6994bc6745fe7b 100644 --- a/ee/spec/lib/remote_development/workspace_operations/create/creator_bootstrapper_spec.rb +++ b/ee/spec/lib/remote_development/workspace_operations/create/creator_bootstrapper_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "fast_spec_helper" -require "ffaker" # rubocop:disable RSpec/VerifiedDoubleReference -- We're using the quoted version so we can use fast_spec_helper RSpec.describe RemoteDevelopment::WorkspaceOperations::Create::CreatorBootstrapper, feature_category: :workspaces do @@ -23,74 +22,24 @@ } end - let(:expected_random_name) { 'peach-blue-whale-red' } + let(:expected_random_name) { 'peach-bluewhale-red' } subject(:returned_value) do described_class.bootstrap(context) end describe "workspace_name" do - let(:expected_workspace_name) { "workspace-#{expected_random_name}" } + let(:expected_workspace_name) { expected_random_name.to_s } let(:shared_namespace) { "" } context "when the generated workspace name is unique" do it "is set in context" do - allow(FFaker::Food).to receive(:fruit).and_return("Peach") - allow(FFaker::AnimalUS).to receive(:common_name).and_return("Blue Whale") - allow(FFaker::Color).to receive(:name).and_return("Red") + stub_const("RemoteDevelopment::WorkspaceOperations::Create::WorkspaceNameGenerator", Class.new) + allow(RemoteDevelopment::WorkspaceOperations::Create::WorkspaceNameGenerator) + .to receive(:generate).and_return("peach-bluewhale-red") - stub_const("RemoteDevelopment::Workspace", Class.new) - allow(RemoteDevelopment::Workspace) - .to receive(:by_names) - .with("workspace-peach-blue-whale-red") - .and_return(instance_double("ActiveRecord::Relation", exists?: false)) - - expect(returned_value.fetch(:workspace_name)).to eq(expected_workspace_name) - end - end - - context "when the generated workspace name is already taken" do - let(:expected_random_name) { 'pear-bald-eagle-green' } - - it "generates another name" do - expect(FFaker::Food).to receive(:fruit).and_return("Peach", "Pear") - expect(FFaker::AnimalUS).to receive(:common_name).and_return("Blue Whale", "Bald Eagle") - expect(FFaker::Color).to receive(:name).and_return("Red", "Green") - - stub_const("RemoteDevelopment::Workspace", Class.new) - expect(RemoteDevelopment::Workspace) - .to receive(:by_names) - .once - .with("workspace-peach-blue-whale-red") - .and_return(instance_double("ActiveRecord::Relation", exists?: true)) - .ordered - expect(RemoteDevelopment::Workspace) - .to receive(:by_names) - .once - .with("workspace-pear-bald-eagle-green") - .and_return(instance_double("ActiveRecord::Relation", exists?: false)) - .ordered expect(returned_value.fetch(:workspace_name)).to eq(expected_workspace_name) end - - context "when the limit of attempts is reached" do - it "raises an error" do - expect(FFaker::Food).to receive(:fruit).exactly(30).times.and_return("Peach") - expect(FFaker::AnimalUS).to receive(:common_name).exactly(30).times.and_return("Blue Whale") - expect(FFaker::Color).to receive(:name).exactly(30).times.and_return("Red") - - stub_const("RemoteDevelopment::Workspace", Class.new) - expect(RemoteDevelopment::Workspace) - .to receive(:by_names) - .exactly(30) - .times - .with("workspace-peach-blue-whale-red") - .and_return(instance_double("ActiveRecord::Relation", exists?: true)) - - expect { returned_value.fetch(:workspace_name) } - .to raise_error(/Unable to generate unique workspace name after 30 attempts/) - end - end end end @@ -99,15 +48,9 @@ let(:shared_namespace) { "" } it "is set in context" do - expect(FFaker::Food).to receive(:fruit).and_return("Peach") - expect(FFaker::AnimalUS).to receive(:common_name).and_return("Blue Whale") - expect(FFaker::Color).to receive(:name).and_return("Red") - - stub_const("RemoteDevelopment::Workspace", Class.new) - allow(RemoteDevelopment::Workspace) - .to receive(:by_names) - .with("workspace-peach-blue-whale-red") - .and_return(instance_double("ActiveRecord::Relation", exists?: false)) + stub_const("RemoteDevelopment::WorkspaceOperations::Create::WorkspaceNameGenerator", Class.new) + allow(RemoteDevelopment::WorkspaceOperations::Create::WorkspaceNameGenerator) + .to receive(:generate).and_return("peach-bluewhale-red") expect(returned_value.fetch(:workspace_namespace)) .to eq("#{create_constants_module::NAMESPACE_PREFIX}-#{expected_random_name}") @@ -118,15 +61,9 @@ let(:shared_namespace) { "my-shared-namespace" } it "is set in context" do - expect(FFaker::Food).to receive(:fruit).and_return("Peach") - expect(FFaker::AnimalUS).to receive(:common_name).and_return("Blue Whale") - expect(FFaker::Color).to receive(:name).and_return("Red") - - stub_const("RemoteDevelopment::Workspace", Class.new) - allow(RemoteDevelopment::Workspace) - .to receive(:by_names) - .with("workspace-peach-blue-whale-red") - .and_return(instance_double("ActiveRecord::Relation", exists?: false)) + stub_const("RemoteDevelopment::WorkspaceOperations::Create::WorkspaceNameGenerator", Class.new) + allow(RemoteDevelopment::WorkspaceOperations::Create::WorkspaceNameGenerator) + .to receive(:generate).and_return("peach-bluewhale-red") expect(returned_value.fetch(:workspace_namespace)).to eq(shared_namespace) end diff --git a/ee/spec/lib/remote_development/workspace_operations/create/main_integration_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/main_integration_spec.rb index fc7a0c49fdef8c..f99941ee9c6c11 100644 --- a/ee/spec/lib/remote_development/workspace_operations/create/main_integration_spec.rb +++ b/ee/spec/lib/remote_development/workspace_operations/create/main_integration_spec.rb @@ -13,7 +13,7 @@ let(:user) { create(:user) } let(:group) { create(:group, name: 'test-group', developers: user) } - let(:random_string) { "miracle-fruit-camel-slategrey" } + let(:random_string) { "miraclefruit-camel-slategrey" } let(:project_ref) { 'master' } let(:devfile_path) { '.devfile.yaml' } let(:devfile_fixture_name) { 'example.devfile.yaml.erb' } @@ -160,7 +160,7 @@ expect(workspace.desired_state_updated_at).to eq(Time.current) expect(workspace.actual_state).to eq(states_module::CREATION_REQUESTED) expect(workspace.actual_state_updated_at).to eq(Time.current) - expect(workspace.name).to eq("workspace-#{random_string}") + expect(workspace.name).to eq(random_string) expect(workspace.namespace) .to eq("#{create_constants_module::NAMESPACE_PREFIX}-#{random_string}") expect(workspace.workspaces_agent_config_version).to eq(expected_workspaces_agent_config_version) diff --git a/ee/spec/lib/remote_development/workspace_operations/create/workspace_name_generator_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/workspace_name_generator_spec.rb new file mode 100644 index 00000000000000..be7cdb71634678 --- /dev/null +++ b/ee/spec/lib/remote_development/workspace_operations/create/workspace_name_generator_spec.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'ffaker' + +RSpec.describe RemoteDevelopment::WorkspaceOperations::Create::WorkspaceNameGenerator, feature_category: :workspaces do + let(:fruit) { 'apple' } + let(:animal) { 'dog' } + let(:color) { 'blue' } + let(:expected_name) { 'apple-dog-blue' } + + context 'when generated name is valid and unique' do + before do + allow(FFaker::Food).to receive(:fruit).and_return(fruit) + allow(FFaker::AnimalUS).to receive(:common_name).and_return(animal) + allow(FFaker::Color).to receive(:name).and_return(color) + stub_const("RemoteDevelopment::Workspace", Class.new) + allow(RemoteDevelopment::Workspace).to receive_message_chain(:by_names, :exists?).and_return(false) + end + + it 'returns a workspace name combining fruit, animal, and color' do + expect(described_class.generate).to eq(expected_name) + end + + it 'converts names to lowercase' do + allow(FFaker::Food).to receive(:fruit).and_return('APPLE') + allow(FFaker::AnimalUS).to receive(:common_name).and_return('DOG') + allow(FFaker::Color).to receive(:name).and_return('BLUE') + + expect(described_class.generate).to eq(expected_name) + end + + it 'parameterizes names to remove spaces' do + allow(FFaker::Food).to receive(:fruit).and_return('Apple') + allow(FFaker::AnimalUS).to receive(:common_name).and_return('Golden Retriever') + allow(FFaker::Color).to receive(:name).and_return('Sky Blue') + + expect(described_class.generate).to eq('apple-goldenretriever-skyblue') + end + end + + context 'when generated name already exists' do + before do + stub_const("RemoteDevelopment::Workspace", Class.new) + end + + it 'retries until finding a unique name' do + stub_const("RemoteDevelopment::Workspace", Class.new) + allow(RemoteDevelopment::Workspace).to receive_message_chain(:by_names, :exists?) + .and_return(true, true, false) + + expect(FFaker::Food).to receive(:fruit).exactly(3).times.and_return(fruit) + expect(FFaker::AnimalUS).to receive(:common_name).exactly(3).times.and_return(animal) + expect(FFaker::Color).to receive(:name).exactly(3).times.and_return(color) + + expect(described_class.generate).to eq(expected_name) + end + end + + context 'when generated name is too long' do + let(:long_fruit) { 'a' * 20 } + let(:long_animal) { 'b' * 20 } + let(:long_color) { 'c' * 20 } + + before do + allow(FFaker::Food).to receive(:fruit).and_return(long_fruit) + allow(FFaker::AnimalUS).to receive(:common_name).and_return(long_animal) + allow(FFaker::Color).to receive(:name).and_return(long_color) + stub_const("RemoteDevelopment::Workspace", Class.new) + allow(RemoteDevelopment::Workspace).to receive_message_chain(:by_names, :exists?).and_return(false) + end + + it 'retries when name exceeds maximum length' do + allow(SecureRandom).to receive(:alphanumeric).with(5).and_return('xyz12') + + result = described_class.generate + + expect(result).to end_with('xyz12') + expect(result.length).to eq(described_class::WORKSPACE_NAME_MAX_LENGTH) + end + end + + context 'when max retries is reached' do + before do + allow(FFaker::Food).to receive(:fruit).and_return(fruit) + allow(FFaker::AnimalUS).to receive(:common_name).and_return(animal) + allow(FFaker::Color).to receive(:name).and_return(color) + + stub_const("RemoteDevelopment::Workspace", Class.new) + allow(RemoteDevelopment::Workspace).to receive_message_chain(:by_names, :exists?).and_return(true) + + allow(SecureRandom).to receive(:alphanumeric).with(5).and_return('abc12') + end + + it 'falls back to truncated name with random string' do + result = described_class.generate + + expect(result).to end_with('abc12') + end + + it 'truncates the original name to make room for random string' do + long_name = 'a' * 40 + allow(FFaker::Food).to receive(:fruit).and_return(long_name) + allow(FFaker::AnimalUS).to receive(:common_name).and_return('') + allow(FFaker::Color).to receive(:name).and_return('') + + result = described_class.generate + expected_truncated_length = described_class::WORKSPACE_NAME_MAX_LENGTH - 1 - + described_class::RANDOM_STRING_LENGTH + + expect(result[0...expected_truncated_length]) + .to eq(long_name.parameterize(separator: "")[0...expected_truncated_length]) + expect(result).to end_with('abc12') + end + end + + describe 'constants' do + it 'has correct RANDOM_STRING_LENGTH' do + expect(described_class::RANDOM_STRING_LENGTH).to eq(5) + end + + it 'has correct WORKSPACE_NAME_MAX_LENGTH' do + expect(described_class::WORKSPACE_NAME_MAX_LENGTH).to eq(34) + end + end +end diff --git a/ee/spec/requests/remote_development/integration_spec.rb b/ee/spec/requests/remote_development/integration_spec.rb index a204c6760b406a..c930a54a3625eb 100644 --- a/ee/spec/requests/remote_development/integration_spec.rb +++ b/ee/spec/requests/remote_development/integration_spec.rb @@ -44,12 +44,12 @@ create(:group, name: "agent-project-group", parent: common_parent_namespace) end - let(:workspace_project_namespace_name) { "workspace-project-group" } + let(:workspace_project_namespace_name) { "project-group" } let(:workspace_project_namespace) do create(:group, name: workspace_project_namespace_name, parent: common_parent_namespace) end - let(:workspace_project_name) { "workspace-project" } + let(:workspace_project_name) { "project" } let(:workspace_namespace_path) { "#{common_parent_namespace_name}/#{workspace_project_namespace_name}" } let(:project_ref) { "master" } let(:devfile_path) { ".devfile.yaml" } @@ -192,7 +192,7 @@ def expected_internal_variables(random_string:, user:) { key: "GL_VSCODE_EXTENSION_MARKETPLACE_ITEM_URL", type: :environment, value: "https://open-vsx.org/vscode/item" }, { key: "GL_VSCODE_EXTENSION_MARKETPLACE_RESOURCE_URL_TEMPLATE", type: :environment, value: "https://open-vsx.org/vscode/unpkg/{publisher}/{name}/{versionRaw}/{path}" }, { key: "GL_VSCODE_EXTENSION_MARKETPLACE_SERVICE_URL", type: :environment, value: "https://open-vsx.org/vscode/gallery" }, - { key: "GL_WORKSPACE_DOMAIN_TEMPLATE", type: :environment, value: "${PORT}-workspace-#{random_string}.#{dns_zone}" }, + { key: "GL_WORKSPACE_DOMAIN_TEMPLATE", type: :environment, value: "${PORT}-#{random_string}.#{dns_zone}" }, { key: "GITLAB_WORKFLOW_INSTANCE_URL", type: :environment, value: Gitlab::Routing.url_helpers.root_url }, { key: "GITLAB_WORKFLOW_TOKEN_FILE", type: :environment, value: token_file_path } ] @@ -415,7 +415,9 @@ def do_create_workspace(random_string_array:, user:) allow(FFaker::AnimalUS).to receive(:common_name).and_return(random_string_array[1]) allow(FFaker::Color).to receive(:name).and_return(random_string_array[2]) - random_string = random_string_array.join("-").parameterize.downcase + random_string = random_string_array + .map { |name_segment| name_segment.parameterize(separator: "") } + .join("-").parameterize.downcase # FETCH THE AGENT CONFIG VIA THE GRAPHQL API, SO WE CAN USE ITS VALUES WHEN CREATING WORKSPACE cluster_agent_gid = "gid://gitlab/Clusters::Agent/#{agent.id}" @@ -437,7 +439,7 @@ def do_create_workspace(random_string_array:, user:) expect(workspace.agent).to eq(agent) # noinspection RubyResolve expect(workspace.desired_state_updated_at).to eq(Time.current) - expect(workspace.name).to eq("workspace-#{random_string}") + expect(workspace.name).to eq(random_string) namespace_prefix = create_constants_module::NAMESPACE_PREFIX expect(workspace.namespace).to eq("#{namespace_prefix}-#{random_string}") expect(workspace.url).to eq(URI::HTTPS.build({ -- GitLab From 37cb64f26204d70f5ebb3029a022882d8a09095d Mon Sep 17 00:00:00 2001 From: Ashvin Sharma Date: Fri, 12 Sep 2025 23:18:11 +0530 Subject: [PATCH 2/3] Add restriction on volume name in devfile --- .../restrictions_enforcer.rb | 20 ++++++++++++++++++- ...e-component-name-too-long-devfile.yaml.erb | 9 +++++++++ .../restrictions_enforcer_spec.rb | 1 + locale/gitlab.pot | 3 +++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 ee/spec/fixtures/remote_development/example.invalid-volume-component-name-too-long-devfile.yaml.erb diff --git a/ee/lib/remote_development/devfile_operations/restrictions_enforcer.rb b/ee/lib/remote_development/devfile_operations/restrictions_enforcer.rb index f0055387595711..2f18de4cc80642 100644 --- a/ee/lib/remote_development/devfile_operations/restrictions_enforcer.rb +++ b/ee/lib/remote_development/devfile_operations/restrictions_enforcer.rb @@ -6,6 +6,8 @@ class RestrictionsEnforcer include RemoteDevelopmentConstants include Messages + MAX_VOLUME_NAME_LIMIT = 28 + MAX_DEVFILE_SIZE_BYTES = 3.megabytes # Since this is called after flattening the devfile, we can safely assume that it has valid syntax @@ -278,6 +280,7 @@ def self.validate_containers(context) context end + # rubocop:enable Metrics/CyclomaticComplexity # @param [Hash] context @@ -478,6 +481,8 @@ def self.validate_component(context, component) context ) end + + validate_volume_component_name(context, component_name) if component.has_key?(:volume) else append_err(_("'Component name' must be a String"), context) end @@ -598,10 +603,23 @@ def self.append_err(message, context) context end + # @param [Hash] context + # @param [String] component_name + # @return [Hash] + def self.validate_volume_component_name(context, component_name) + return unless component_name.length >= MAX_VOLUME_NAME_LIMIT + + details = format(_("Volume's name must be less than %{character_limit} characters"), + character_limit: MAX_VOLUME_NAME_LIMIT + ) + + append_err(_(details), context) + end + private_class_method :validate_devfile_size, :validate_schema_version, :validate_parent, :validate_projects, :validate_root_attributes, :validate_components, :validate_containers, :validate_endpoints, :validate_commands, :validate_command_restricted_prefix, :validate_events, - :validate_variables, :validate_component, :validate_command, :append_err + :validate_variables, :validate_component, :validate_command, :append_err, :validate_volume_component_name end end end diff --git a/ee/spec/fixtures/remote_development/example.invalid-volume-component-name-too-long-devfile.yaml.erb b/ee/spec/fixtures/remote_development/example.invalid-volume-component-name-too-long-devfile.yaml.erb new file mode 100644 index 00000000000000..c0e75d4708784f --- /dev/null +++ b/ee/spec/fixtures/remote_development/example.invalid-volume-component-name-too-long-devfile.yaml.erb @@ -0,0 +1,9 @@ +--- +schemaVersion: 2.2.0 +components: + - name: this-volume-name-is-way-too-long-for-kubernetes-to-handle-properly + volume: + size: 42Gi +commands: [] +events: {} +variables: {} diff --git a/ee/spec/lib/remote_development/devfile_operations/restrictions_enforcer_spec.rb b/ee/spec/lib/remote_development/devfile_operations/restrictions_enforcer_spec.rb index b196054a6d2785..7270e9c3879464 100644 --- a/ee/spec/lib/remote_development/devfile_operations/restrictions_enforcer_spec.rb +++ b/ee/spec/lib/remote_development/devfile_operations/restrictions_enforcer_spec.rb @@ -128,6 +128,7 @@ "example.invalid-unsupported-starter-projects-devfile.yaml.erb" | "'starterProjects' is not yet supported" | :processed_devfile "example.invalid-unsupported-component-container-source-mapping-devfile.yaml.erb" | "Property 'sourceMapping' of component 'example' is not yet supported" | :processed_devfile "example.invalid-unsupported-component-container-mount-sources-devfile.yaml.erb" | "Property 'mountSources' of component 'example' is not yet supported" | :devfile + "example.invalid-volume-component-name-too-long-devfile.yaml.erb" | "Volume's name must be less than #{described_class::MAX_VOLUME_NAME_LIMIT} characters" | :processed_devfile end # rubocop:enable Layout/LineLength diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 6631589bb77eb9..66c9d1ba0d7700 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -71572,6 +71572,9 @@ msgstr "" msgid "Visual Studio Code (SSH)" msgstr "" +msgid "Volume's name must be less than %{character_limit} characters" +msgstr "" + msgid "VsdContributorCount|the ClickHouse data store is not available for this namespace" msgstr "" -- GitLab From 7779357511862ae5fb189ebd238cd69ad81fc869 Mon Sep 17 00:00:00 2001 From: Ashvin Sharma Date: Fri, 12 Sep 2025 23:38:01 +0530 Subject: [PATCH 3/3] Refactor random_string_* variable in creator_bootstrapper_spec and remote_development/integration_spec --- .../create/creator_bootstrapper.rb | 2 -- .../create/creator_bootstrapper_spec.rb | 5 ++--- .../remote_development/integration_spec.rb | 16 ++++++++-------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/ee/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb b/ee/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb index 300760b249a85e..04f55bd9b99fdd 100644 --- a/ee/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb +++ b/ee/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb @@ -6,8 +6,6 @@ module Create class CreatorBootstrapper include CreateConstants - RANDOM_STRING_LENGTH = 5 - # @param [Hash] context # @return [Hash] def self.bootstrap(context) diff --git a/ee/spec/lib/remote_development/workspace_operations/create/creator_bootstrapper_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/creator_bootstrapper_spec.rb index 6994bc6745fe7b..644f475c794e0e 100644 --- a/ee/spec/lib/remote_development/workspace_operations/create/creator_bootstrapper_spec.rb +++ b/ee/spec/lib/remote_development/workspace_operations/create/creator_bootstrapper_spec.rb @@ -22,14 +22,13 @@ } end - let(:expected_random_name) { 'peach-bluewhale-red' } + let(:expected_workspace_name) { 'peach-bluewhale-red' } subject(:returned_value) do described_class.bootstrap(context) end describe "workspace_name" do - let(:expected_workspace_name) { expected_random_name.to_s } let(:shared_namespace) { "" } context "when the generated workspace name is unique" do @@ -53,7 +52,7 @@ .to receive(:generate).and_return("peach-bluewhale-red") expect(returned_value.fetch(:workspace_namespace)) - .to eq("#{create_constants_module::NAMESPACE_PREFIX}-#{expected_random_name}") + .to eq("#{create_constants_module::NAMESPACE_PREFIX}-#{expected_workspace_name}") end end diff --git a/ee/spec/requests/remote_development/integration_spec.rb b/ee/spec/requests/remote_development/integration_spec.rb index c930a54a3625eb..e6b7f8dc4bb758 100644 --- a/ee/spec/requests/remote_development/integration_spec.rb +++ b/ee/spec/requests/remote_development/integration_spec.rb @@ -407,15 +407,15 @@ def do_create_org_mapping end # rubocop:disable Metrics/AbcSize -- We want this to stay a single method - # @param [Array] random_string_array + # @param [Array] workspace_name_parts # @param [User, QA::Resource::User] user # @return [RemoteDevelopment::Workspace] - def do_create_workspace(random_string_array:, user:) - allow(FFaker::Food).to receive(:fruit).and_return(random_string_array[0]) - allow(FFaker::AnimalUS).to receive(:common_name).and_return(random_string_array[1]) - allow(FFaker::Color).to receive(:name).and_return(random_string_array[2]) + def do_create_workspace(workspace_name_parts:, user:) + allow(FFaker::Food).to receive(:fruit).and_return(workspace_name_parts[0]) + allow(FFaker::AnimalUS).to receive(:common_name).and_return(workspace_name_parts[1]) + allow(FFaker::Color).to receive(:name).and_return(workspace_name_parts[2]) - random_string = random_string_array + random_string = workspace_name_parts .map { |name_segment| name_segment.parameterize(separator: "") } .join("-").parameterize.downcase @@ -601,7 +601,7 @@ def do_reconcile_post(params:, agent_token:) do_create_workspaces_agent_config # CREATE WORKSPACE VIA GRAPHQL API - workspace = do_create_workspace(random_string_array: %w[Date Butterfly Darkturquoise], user: user) + workspace = do_create_workspace(workspace_name_parts: %w[Date Butterfly Darkturquoise], user: user) additional_args_for_expected_config_to_apply = build_additional_args_for_expected_config_to_apply_yaml_stream( @@ -747,7 +747,7 @@ def do_reconcile_post(params:, agent_token:) do_create_org_mapping # CREATE A NEW WORKSPACE WITH THE ORGANIZATION MAPPING WITH MINIMUM USER PRIVILEGES - do_create_workspace(random_string_array: ["Peach", "Blue Whale", "Red"], user: organization_user) + do_create_workspace(workspace_name_parts: ["Peach", "Blue Whale", "Red"], user: organization_user) end end -- GitLab