diff --git a/ee/lib/remote_development/devfile_operations/restrictions_enforcer.rb b/ee/lib/remote_development/devfile_operations/restrictions_enforcer.rb index f0055387595711d98ac20f095bc10e451137af09..2f18de4cc80642e4a3dc5473a5705af1645dccb1 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/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb b/ee/lib/remote_development/workspace_operations/create/creator_bootstrapper.rb index 46bfe152970a8854323bcd6ae99af9a96f19281c..04f55bd9b99fddcc33bc2580e60327c700905a82 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 = 6 - # @param [Hash] context # @return [Hash] def self.bootstrap(context) @@ -18,9 +16,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 +24,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 +35,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 0000000000000000000000000000000000000000..24ddfeed57b8e0fd2d32089363e50215f4e81eef --- /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/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 0000000000000000000000000000000000000000..c0e75d4708784f10901fa2b5d8f1f00b40a0002c --- /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 b196054a6d2785a2f502d4c1bc231db72d4d496f..7270e9c3879464d29deb425ed29c8b64730f9e96 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/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 eb60c8e335089af58ebed7b2ae5094af7d428323..644f475c794e0ec0f3039ac80107385cabb48f35 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,23 @@ } end - let(:expected_random_name) { 'peach-blue-whale-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) { "workspace-#{expected_random_name}" } 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,18 +47,12 @@ 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}") + .to eq("#{create_constants_module::NAMESPACE_PREFIX}-#{expected_workspace_name}") end end @@ -118,15 +60,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 fc7a0c49fdef8c77740f406bfe3535754a685fb0..f99941ee9c6c114f3b3fa3c557c43040c11b2278 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 0000000000000000000000000000000000000000..be7cdb716346785c469cdf09d7a7748f8152764b --- /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 a204c6760b406a6d709c7f9d3b893ed3a32d3975..e6b7f8dc4bb75812563ceab57851e6ea2e59566a 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 } ] @@ -407,15 +407,17 @@ 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.join("-").parameterize.downcase + random_string = workspace_name_parts + .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({ @@ -599,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( @@ -745,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 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 6631589bb77eb9c71d26a81c4bd9de05a1adc998..66c9d1ba0d7700a8033b8447f5f61de91b8d6fca 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 ""