diff --git a/ee/lib/remote_development/README.md b/ee/lib/remote_development/README.md index cc126c83e749466fd3e7be3810ca45f58c96d631..bc2b5b534e221f0e3ee06d3fdf5f094079e10367 100644 --- a/ee/lib/remote_development/README.md +++ b/ee/lib/remote_development/README.md @@ -581,11 +581,11 @@ The `invoke_rop_steps` method is the entry into the matcher. It accepts as a par ```ruby let(:rop_steps) do - [ - [RemoteDevelopment::WorkspaceOperations::Create::VolumeComponentInjector, :map], - [RemoteDevelopment::WorkspaceOperations::Create::Creator, :and_then] - ] - end + [ + [RemoteDevelopment::WorkspaceOperations::Create::VolumeComponentInserter, :map], + [RemoteDevelopment::WorkspaceOperations::Create::Creator, :and_then] + ] +end ``` It expects the array to specify step classes in the same order as the chain of the ROP main class being tested. It returns a `match` block that will be configured by matcher chain methods. diff --git a/ee/lib/remote_development/workspace_operations/create/main.rb b/ee/lib/remote_development/workspace_operations/create/main.rb index 48169e0f2a8828cf9f8d0203e5dc0da29090d848..7a42e3c15804a2ed6a2ebd24b94cff80db7956bf 100644 --- a/ee/lib/remote_development/workspace_operations/create/main.rb +++ b/ee/lib/remote_development/workspace_operations/create/main.rb @@ -21,9 +21,10 @@ def self.main(context) .and_then(DevfileFlattener.method(:flatten)) .and_then(PostFlattenDevfileValidator.method(:validate)) .map(VolumeDefiner.method(:define)) - .map(ToolsComponentInjector.method(:inject)) - .map(ProjectClonerComponentInjector.method(:inject)) - .map(VolumeComponentInjector.method(:inject)) + .map(ToolsInjectorComponentInserter.method(:insert)) + .map(MainComponentUpdater.method(:update)) + .map(ProjectClonerComponentInserter.method(:insert)) + .map(VolumeComponentInserter.method(:insert)) .and_then(Creator.method(:create)) # rubocop:disable Lint/DuplicateBranch -- Rubocop doesn't know the branches are different due to destructuring diff --git a/ee/lib/remote_development/workspace_operations/create/main_component_updater.rb b/ee/lib/remote_development/workspace_operations/create/main_component_updater.rb new file mode 100644 index 0000000000000000000000000000000000000000..11635154750b089e6d7d05bcd4862816987ce9ca --- /dev/null +++ b/ee/lib/remote_development/workspace_operations/create/main_component_updater.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +module RemoteDevelopment + module WorkspaceOperations + module Create + class MainComponentUpdater + include Messages + + # @param [Hash] context + # @return [Hash] + def self.update(context) + context => { + processed_devfile: Hash => processed_devfile, + volume_mounts: Hash => volume_mounts, + vscode_extensions_gallery_metadata: Hash => vscode_extensions_gallery_metadata + } + volume_mounts => { data_volume: Hash => data_volume } + data_volume => { path: String => volume_path } + + editor_port = WorkspaceCreator::WORKSPACE_PORT + ssh_port = 60022 + tools_dir = "#{volume_path}/.gl-tools" + + # NOTE: We will always have exactly one main_component found, because we have already + # validated this in post_flatten_devfile_validator.rb + main_component = processed_devfile['components'].find { |c| c.dig('attributes', 'gl/inject-editor') } + + update_main_container( + main_component: main_component, + tools_dir: tools_dir, + editor_port: editor_port, + ssh_port: ssh_port, + enable_marketplace: vscode_extensions_gallery_metadata.fetch(:enabled) + ) + + context + end + + # @param [Hash] main_component + # @param [String] tools_dir + # @param [Integer] editor_port + # @param [Integer] ssh_port + # @param [Boolean] enable_marketplace + # @return [void] + def self.update_main_container(main_component:, tools_dir:, editor_port:, ssh_port:, enable_marketplace:) + # This overrides the main container's command + # Open issue to support both starting the editor and running the default command: + # https://gitlab.com/gitlab-org/gitlab/-/issues/392853 + container_args = <<~"SH".chomp + sshd_path=$(which sshd) + if [ -x "$sshd_path" ]; then + echo "Starting sshd on port ${GL_SSH_PORT}" + $sshd_path -D -p $GL_SSH_PORT & + else + echo "'sshd' not found in path. Not starting SSH server." + fi + ${GL_TOOLS_DIR}/init_tools.sh + SH + main_component['container']['command'] = %w[/bin/sh -c] + main_component['container']['args'] = [container_args] + main_component['container']['env'] = [] if main_component['container']['env'].nil? + main_component['container']['env'] += [ + { + 'name' => 'GL_TOOLS_DIR', + 'value' => tools_dir + }, + { + 'name' => 'GL_EDITOR_LOG_LEVEL', + 'value' => 'info' + }, + { + 'name' => 'GL_EDITOR_PORT', + 'value' => editor_port.to_s + }, + { + 'name' => 'GL_SSH_PORT', + 'value' => ssh_port.to_s + }, + { + 'name' => 'GL_EDITOR_ENABLE_MARKETPLACE', + 'value' => enable_marketplace.to_s + } + ] + + main_component['container']['endpoints'] = [] if main_component['container']['endpoints'].nil? + main_component['container']['endpoints'].append( + { + 'name' => 'editor-server', + 'targetPort' => editor_port, + 'exposure' => 'public', + 'secure' => true, + 'protocol' => 'https' + }, + { + 'name' => 'ssh-server', + 'targetPort' => ssh_port, + 'exposure' => 'internal', + 'secure' => true + } + ) + end + + private_class_method :update_main_container + end + end + end +end diff --git a/ee/lib/remote_development/workspace_operations/create/post_flatten_devfile_validator.rb b/ee/lib/remote_development/workspace_operations/create/post_flatten_devfile_validator.rb index 4c3fc59a1f984befb6277db115e0ee7699efd686..4e3c479e2fd85642f1b846adc2e36a6e1e0c9685 100644 --- a/ee/lib/remote_development/workspace_operations/create/post_flatten_devfile_validator.rb +++ b/ee/lib/remote_development/workspace_operations/create/post_flatten_devfile_validator.rb @@ -69,17 +69,17 @@ def self.validate_components(context) return err(_('No components present in devfile')) if components.blank? - injected_tools_components = components.select do |component| + injected_main_components = components.select do |component| component.dig('attributes', 'gl/inject-editor') end - return err(_("No component has 'gl/inject-editor' attribute")) if injected_tools_components.empty? + return err(_("No component has 'gl/inject-editor' attribute")) if injected_main_components.empty? - if injected_tools_components.length > 1 + if injected_main_components.length > 1 return err( format( _("Multiple components '%{name}' have 'gl/inject-editor' attribute"), - name: injected_tools_components.pluck('name') # rubocop:disable CodeReuse/ActiveRecord -- this pluck isn't from ActiveRecord, it's from ActiveSupport + name: injected_main_components.pluck('name') # rubocop:disable CodeReuse/ActiveRecord -- this pluck isn't from ActiveRecord, it's from ActiveSupport ) ) end diff --git a/ee/lib/remote_development/workspace_operations/create/project_cloner_component_injector.rb b/ee/lib/remote_development/workspace_operations/create/project_cloner_component_inserter.rb similarity index 95% rename from ee/lib/remote_development/workspace_operations/create/project_cloner_component_injector.rb rename to ee/lib/remote_development/workspace_operations/create/project_cloner_component_inserter.rb index 1813da2d51d4097ef6ae2b5e8f6ebd22a3a636a5..e840e3c7da6d58ed5c087827833e1f58206d5398 100644 --- a/ee/lib/remote_development/workspace_operations/create/project_cloner_component_injector.rb +++ b/ee/lib/remote_development/workspace_operations/create/project_cloner_component_inserter.rb @@ -3,12 +3,12 @@ module RemoteDevelopment module WorkspaceOperations module Create - class ProjectClonerComponentInjector + class ProjectClonerComponentInserter include Messages # @param [Hash] context # @return [Hash] - def self.inject(context) + def self.insert(context) context => { processed_devfile: Hash => processed_devfile, volume_mounts: Hash => volume_mounts, @@ -18,7 +18,7 @@ def self.inject(context) volume_mounts => { data_volume: Hash => data_volume } data_volume => { path: String => volume_path } params => { - project: Project => project, + project: project, devfile_ref: String => devfile_ref, } settings => { @@ -70,7 +70,7 @@ def self.inject(context) # implement better error handling to allow cloner to be able to deal with different categories of errors # issue: https://gitlab.com/gitlab-org/gitlab/-/issues/408451 cloner_component = { - 'name' => 'gl-cloner-injector', + 'name' => 'gl-project-cloner', 'container' => { 'image' => image, 'args' => [container_args], @@ -95,7 +95,7 @@ def self.inject(context) # create a command that will invoke the cloner cloner_command = { - 'id' => 'gl-cloner-injector-command', + 'id' => 'gl-project-cloner-command', 'apply' => { 'component' => cloner_component['name'] } diff --git a/ee/lib/remote_development/workspace_operations/create/tools_component_injector.rb b/ee/lib/remote_development/workspace_operations/create/tools_component_injector.rb deleted file mode 100644 index 32c4c911a32a290bde6412b925bc37842bd22ac8..0000000000000000000000000000000000000000 --- a/ee/lib/remote_development/workspace_operations/create/tools_component_injector.rb +++ /dev/null @@ -1,158 +0,0 @@ -# frozen_string_literal: true - -module RemoteDevelopment - module WorkspaceOperations - module Create - class ToolsComponentInjector - include Messages - - # @param [Hash] context - # @return [Hash] - def self.inject(context) - context => { - processed_devfile: Hash => processed_devfile, - volume_mounts: Hash => volume_mounts, - settings: Hash => settings, - vscode_extensions_gallery_metadata: Hash => vscode_extensions_gallery_metadata - } - volume_mounts => { data_volume: Hash => data_volume } - data_volume => { path: String => volume_path } - settings => { tools_injector_image: String => image_from_settings } - - editor_port = WorkspaceCreator::WORKSPACE_PORT - ssh_port = 60022 - tools_dir = "#{volume_path}/.gl-tools" - # NOTE: We will always have exactly one tools_component found, because we have already - # validated this in post_flatten_devfile_validator.rb - tools_component = processed_devfile['components'].find { |c| c.dig('attributes', 'gl/inject-editor') } - - # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/409775 - choose image based on which editor is passed. - inject_tools_components( - processed_devfile: processed_devfile, - tools_dir: tools_dir, - image: image_from_settings - ) - - override_main_container( - tools_component: tools_component, - tools_dir: tools_dir, - editor_port: editor_port, - ssh_port: ssh_port, - enable_marketplace: vscode_extensions_gallery_metadata.fetch(:enabled) - ) - - context - end - - # @param [Hash] tools_component - # @param [String] tools_dir - # @param [Integer] editor_port - # @param [Integer] ssh_port - # @param [Boolean] enable_marketplace - # @return [void] - def self.override_main_container(tools_component:, tools_dir:, editor_port:, ssh_port:, enable_marketplace:) - # This overrides the main container's command - # Open issue to support both starting the editor and running the default command: - # https://gitlab.com/gitlab-org/gitlab/-/issues/392853 - container_args = <<~"SH".chomp - sshd_path=$(which sshd) - if [ -x "$sshd_path" ]; then - echo "Starting sshd on port ${GL_SSH_PORT}" - $sshd_path -D -p $GL_SSH_PORT & - else - echo "'sshd' not found in path. Not starting SSH server." - fi - ${GL_TOOLS_DIR}/init_tools.sh - SH - tools_component['container']['command'] = %w[/bin/sh -c] - tools_component['container']['args'] = [container_args] - tools_component['container']['env'] = [] if tools_component['container']['env'].nil? - tools_component['container']['env'] += [ - { - 'name' => 'GL_TOOLS_DIR', - 'value' => tools_dir - }, - { - 'name' => 'GL_EDITOR_LOG_LEVEL', - 'value' => 'info' - }, - { - 'name' => 'GL_EDITOR_PORT', - 'value' => editor_port.to_s - }, - { - 'name' => 'GL_SSH_PORT', - 'value' => ssh_port.to_s - }, - { - 'name' => 'GL_EDITOR_ENABLE_MARKETPLACE', - 'value' => enable_marketplace.to_s - } - ] - - tools_component['container']['endpoints'] = [] if tools_component['container']['endpoints'].nil? - tools_component['container']['endpoints'].append( - { - 'name' => 'editor-server', - 'targetPort' => editor_port, - 'exposure' => 'public', - 'secure' => true, - 'protocol' => 'https' - }, - { - 'name' => 'ssh-server', - 'targetPort' => ssh_port, - 'exposure' => 'internal', - 'secure' => true - } - ) - end - - # @param [Hash] processed_devfile - # @param [String] tools_dir - # @param [String] image - # @return [Array] - def self.inject_tools_components(processed_devfile:, tools_dir:, image:) - processed_devfile['components'] += tools_components(tools_dir: tools_dir, image: image) - - processed_devfile['commands'] = [] if processed_devfile['commands'].nil? - processed_devfile['commands'] += [{ - 'id' => 'gl-tools-injector-command', - 'apply' => { - 'component' => 'gl-tools-injector' - } - }] - - processed_devfile['events'] = {} if processed_devfile['events'].nil? - processed_devfile['events']['preStart'] = [] if processed_devfile['events']['preStart'].nil? - processed_devfile['events']['preStart'] += ['gl-tools-injector-command'] - end - - # @param [String] tools_dir - # @param [String] image - # @return [Array] - def self.tools_components(tools_dir:, image:) - [ - { - 'name' => 'gl-tools-injector', - 'container' => { - 'image' => image, - 'env' => [ - { - 'name' => 'GL_TOOLS_DIR', - 'value' => tools_dir - } - ], - 'memoryLimit' => '512Mi', - 'memoryRequest' => '256Mi', - 'cpuLimit' => '500m', - 'cpuRequest' => '100m' - } - } - ] - end - private_class_method :override_main_container, :inject_tools_components, :tools_components - end - end - end -end diff --git a/ee/lib/remote_development/workspace_operations/create/tools_injector_component_inserter.rb b/ee/lib/remote_development/workspace_operations/create/tools_injector_component_inserter.rb new file mode 100644 index 0000000000000000000000000000000000000000..4123e5436216e51f3c41cf9b410617a0871d364e --- /dev/null +++ b/ee/lib/remote_development/workspace_operations/create/tools_injector_component_inserter.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +module RemoteDevelopment + module WorkspaceOperations + module Create + class ToolsInjectorComponentInserter + include Messages + + # @param [Hash] context + # @return [Hash] + def self.insert(context) + context => { + processed_devfile: Hash => processed_devfile, + volume_mounts: Hash => volume_mounts, + settings: Hash => settings, + } + volume_mounts => { data_volume: Hash => data_volume } + data_volume => { path: String => volume_path } + settings => { tools_injector_image: String => image_from_settings } + + tools_dir = "#{volume_path}/.gl-tools" + # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/409775 - choose image based on which editor is passed. + insert_tools_injector_component( + processed_devfile: processed_devfile, + tools_dir: tools_dir, + image: image_from_settings + ) + + context + end + + # @param [Hash] processed_devfile + # @param [String] tools_dir + # @param [String] image + # @return [void] + def self.insert_tools_injector_component(processed_devfile:, tools_dir:, image:) + component_name = 'gl-tools-injector' + + tools_injector_component = { + 'name' => component_name, + 'container' => { + 'image' => image, + 'env' => [ + { + 'name' => 'GL_TOOLS_DIR', + 'value' => tools_dir + } + ], + 'memoryLimit' => '512Mi', + 'memoryRequest' => '256Mi', + 'cpuLimit' => '500m', + 'cpuRequest' => '100m' + } + } + processed_devfile['components'] << tools_injector_component + + processed_devfile['commands'] = [] if processed_devfile['commands'].nil? + + command_name = "#{component_name}-command" + processed_devfile['commands'] += [{ + 'id' => command_name, + 'apply' => { + 'component' => component_name + } + }] + + processed_devfile['events'] = {} if processed_devfile['events'].nil? + processed_devfile['events']['preStart'] = [] if processed_devfile['events']['preStart'].nil? + processed_devfile['events']['preStart'] += [command_name] + + nil + end + + private_class_method :insert_tools_injector_component + end + end + end +end diff --git a/ee/lib/remote_development/workspace_operations/create/volume_component_injector.rb b/ee/lib/remote_development/workspace_operations/create/volume_component_inserter.rb similarity index 94% rename from ee/lib/remote_development/workspace_operations/create/volume_component_injector.rb rename to ee/lib/remote_development/workspace_operations/create/volume_component_inserter.rb index 774f94ed2d84b390db654898b85e874bccc53f8b..a317702c6b054836312ad291eaf5322ecc1fa333 100644 --- a/ee/lib/remote_development/workspace_operations/create/volume_component_injector.rb +++ b/ee/lib/remote_development/workspace_operations/create/volume_component_inserter.rb @@ -3,12 +3,12 @@ module RemoteDevelopment module WorkspaceOperations module Create - class VolumeComponentInjector + class VolumeComponentInserter include Messages # @param [Hash] context # @return [Hash] - def self.inject(context) + def self.insert(context) context => { processed_devfile: Hash => processed_devfile, volume_mounts: Hash => volume_mounts } volume_mounts => { data_volume: Hash => data_volume } data_volume => { diff --git a/ee/spec/fixtures/remote_development/example.invalid-unsupported-projects-devfile.yaml b/ee/spec/fixtures/remote_development/example.invalid-unsupported-projects-devfile.yaml index 57db7a7cb6291d63e21986dfa8f22df914e00351..1860462307921840fd785abe1d152cb748c93f71 100644 --- a/ee/spec/fixtures/remote_development/example.invalid-unsupported-projects-devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.invalid-unsupported-projects-devfile.yaml @@ -7,7 +7,7 @@ projects: remote: origin revision: main remotes: - origin: https://example.com/path/to/repository + origin: http://localhost/path/to/repository subDir: app components: - name: example diff --git a/ee/spec/fixtures/remote_development/example.invalid-unsupported-starter-projects-devfile.yaml b/ee/spec/fixtures/remote_development/example.invalid-unsupported-starter-projects-devfile.yaml index 3f1e8fabf5acac51dc88b2e6b1bf7bc4478cdb2e..71a59e5057317f61fee941320055f66211f1a810 100644 --- a/ee/spec/fixtures/remote_development/example.invalid-unsupported-starter-projects-devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.invalid-unsupported-starter-projects-devfile.yaml @@ -7,7 +7,7 @@ starterProjects: remote: origin revision: main remotes: - origin: https://example.com/path/to/repository + origin: http://localhost/path/to/repository subDir: app components: - name: example diff --git a/ee/spec/fixtures/remote_development/example.tools-injected-devfile.yaml b/ee/spec/fixtures/remote_development/example.main-container-updated-devfile.yaml similarity index 100% rename from ee/spec/fixtures/remote_development/example.tools-injected-devfile.yaml rename to ee/spec/fixtures/remote_development/example.main-container-updated-devfile.yaml diff --git a/ee/spec/fixtures/remote_development/example.tools-injected-marketplace-disabled-devfile.yaml b/ee/spec/fixtures/remote_development/example.main-container-updated-marketplace-disabled-devfile.yaml similarity index 100% rename from ee/spec/fixtures/remote_development/example.tools-injected-marketplace-disabled-devfile.yaml rename to ee/spec/fixtures/remote_development/example.main-container-updated-marketplace-disabled-devfile.yaml diff --git a/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml b/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml index ff06803b6daf91feec35b51b1dfb37953b83d165..2566972d882eb59263c920c92bf272a9d98e26c2 100644 --- a/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml +++ b/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml @@ -70,7 +70,7 @@ components: memoryRequest: 256Mi cpuLimit: 500m cpuRequest: 100m - - name: gl-cloner-injector + - name: gl-project-cloner container: image: alpine/git:2.45.2 volumeMounts: @@ -117,11 +117,11 @@ components: events: preStart: - gl-tools-injector-command - - gl-cloner-injector-command + - gl-project-cloner-command commands: - id: gl-tools-injector-command apply: component: gl-tools-injector - - id: gl-cloner-injector-command + - id: gl-project-cloner-command apply: - component: gl-cloner-injector + component: gl-project-cloner diff --git a/ee/spec/fixtures/remote_development/example.processed-devfile.yaml b/ee/spec/fixtures/remote_development/example.processed-devfile.yaml index ff06803b6daf91feec35b51b1dfb37953b83d165..2566972d882eb59263c920c92bf272a9d98e26c2 100644 --- a/ee/spec/fixtures/remote_development/example.processed-devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.processed-devfile.yaml @@ -70,7 +70,7 @@ components: memoryRequest: 256Mi cpuLimit: 500m cpuRequest: 100m - - name: gl-cloner-injector + - name: gl-project-cloner container: image: alpine/git:2.45.2 volumeMounts: @@ -117,11 +117,11 @@ components: events: preStart: - gl-tools-injector-command - - gl-cloner-injector-command + - gl-project-cloner-command commands: - id: gl-tools-injector-command apply: component: gl-tools-injector - - id: gl-cloner-injector-command + - id: gl-project-cloner-command apply: - component: gl-cloner-injector + component: gl-project-cloner diff --git a/ee/spec/fixtures/remote_development/example.processed-marketplace-disabled-devfile.yaml b/ee/spec/fixtures/remote_development/example.processed-marketplace-disabled-devfile.yaml deleted file mode 100644 index 4c4fe5f155207431227547c1984a4d356a524d1d..0000000000000000000000000000000000000000 --- a/ee/spec/fixtures/remote_development/example.processed-marketplace-disabled-devfile.yaml +++ /dev/null @@ -1,116 +0,0 @@ ---- -schemaVersion: 2.2.0 -metadata: {} -components: - - name: tooling-container - attributes: - gl/inject-editor: true - container: - image: quay.io/mloriedo/universal-developer-image:ubi8-dw-demo - args: - - |- - sshd_path=$(which sshd) - if [ -x "$sshd_path" ]; then - echo "Starting sshd on port ${GL_SSH_PORT}" - $sshd_path -D -p $GL_SSH_PORT & - else - echo "'sshd' not found in path. Not starting SSH server." - fi - ${GL_TOOLS_DIR}/init_tools.sh - command: - - "/bin/sh" - - "-c" - volumeMounts: - - name: gl-workspace-data - path: /projects - env: - - name: GL_TOOLS_DIR - value: "/projects/.gl-tools" - - name: GL_EDITOR_LOG_LEVEL - value: "info" - - name: GL_EDITOR_PORT - value: "60001" - - name: GL_SSH_PORT - value: "60022" - - name: GL_EDITOR_ENABLE_MARKETPLACE - value: "false" - endpoints: - - name: editor-server - targetPort: 60001 - exposure: public - secure: true - protocol: https - - name: ssh-server - targetPort: 60022 - exposure: internal - secure: true - dedicatedPod: false - mountSources: true - - name: gl-workspace-data - volume: - size: 50Gi - - name: gl-tools-injector - container: - image: registry.gitlab.com/gitlab-org/remote-development/gitlab-workspaces-tools:2.0.0 - volumeMounts: - - name: gl-workspace-data - path: /projects - env: - - name: GL_TOOLS_DIR - value: "/projects/.gl-tools" - memoryLimit: 512Mi - memoryRequest: 256Mi - cpuLimit: 500m - cpuRequest: 100m - - name: gl-cloner-injector - container: - image: alpine/git:2.45.2 - volumeMounts: - - name: gl-workspace-data - path: "/projects" - env: - - name: GL_PROJECT_CLONING_SUCCESSFUL_FILE - value: "/projects/.gl_project_cloning_successful" - args: - - |- - if [ -f "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}" ]; - then - echo "Project cloning was already successful"; - exit 0; - fi - if [ -d "/projects/test-project" ]; - then - echo "Removing unsuccessfully cloned project directory"; - rm -rf "/projects/test-project"; - fi - echo "Cloning project"; - git clone --branch "master" "http://localhost/test-group/test-project.git" "/projects/test-project"; - exit_code=$? - if [ "${exit_code}" -eq 0 ]; - then - echo "Project cloning successful"; - touch "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}"; - echo "Updated file to indicate successful project cloning"; - exit 0; - else - echo "Project cloning failed with exit code: ${exit_code}"; - exit "${exit_code}"; - fi - command: - - "/bin/sh" - - "-c" - memoryLimit: 512Mi - memoryRequest: 256Mi - cpuLimit: 500m - cpuRequest: 100m -events: - preStart: - - gl-tools-injector-command - - gl-cloner-injector-command -commands: - - id: gl-tools-injector-command - apply: - component: gl-tools-injector - - id: gl-cloner-injector-command - apply: - component: gl-cloner-injector diff --git a/ee/spec/fixtures/remote_development/example.project-cloner-injected-devfile.yaml b/ee/spec/fixtures/remote_development/example.project-cloner-inserted-devfile.yaml similarity index 95% rename from ee/spec/fixtures/remote_development/example.project-cloner-injected-devfile.yaml rename to ee/spec/fixtures/remote_development/example.project-cloner-inserted-devfile.yaml index 4b1bc57d3b5a4e08798aeeeac2314dff6b32c76c..287ab95cd8b86a2dd25d570299653655f39bbf34 100644 --- a/ee/spec/fixtures/remote_development/example.project-cloner-injected-devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.project-cloner-inserted-devfile.yaml @@ -61,7 +61,7 @@ components: memoryRequest: 256Mi cpuLimit: 500m cpuRequest: 100m - - name: gl-cloner-injector + - name: gl-project-cloner container: image: alpine/git:2.45.2 env: @@ -102,11 +102,11 @@ components: events: preStart: - gl-tools-injector-command - - gl-cloner-injector-command + - gl-project-cloner-command commands: - id: gl-tools-injector-command apply: component: gl-tools-injector - - id: gl-cloner-injector-command + - id: gl-project-cloner-command apply: - component: gl-cloner-injector + component: gl-project-cloner diff --git a/ee/spec/fixtures/remote_development/example.tools-injector-inserted-devfile.yaml b/ee/spec/fixtures/remote_development/example.tools-injector-inserted-devfile.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8b1dcc80e29f970b0897330f461fa5ca24acce49 --- /dev/null +++ b/ee/spec/fixtures/remote_development/example.tools-injector-inserted-devfile.yaml @@ -0,0 +1,36 @@ +--- +schemaVersion: 2.2.0 +metadata: {} +components: + - name: tooling-container + attributes: + gl/inject-editor: true + container: + image: quay.io/mloriedo/universal-developer-image:ubi8-dw-demo + dedicatedPod: false + mountSources: true + - name: database-container + container: + image: mysql + env: + - name: MYSQL_ROOT_PASSWORD + value: "my-secret-pw" + dedicatedPod: false + mountSources: true + - name: gl-tools-injector + container: + image: registry.gitlab.com/gitlab-org/remote-development/gitlab-workspaces-tools:2.0.0 + env: + - name: GL_TOOLS_DIR + value: "/projects/.gl-tools" + memoryLimit: 512Mi + memoryRequest: 256Mi + cpuLimit: 500m + cpuRequest: 100m +events: + preStart: + - gl-tools-injector-command +commands: + - id: gl-tools-injector-command + apply: + component: gl-tools-injector diff --git a/ee/spec/lib/remote_development/workspace_operations/create/main_component_updater_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/main_component_updater_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..63d2ca6e7597bca1f8f83967360cd55857cc4114 --- /dev/null +++ b/ee/spec/lib/remote_development/workspace_operations/create/main_component_updater_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require "fast_spec_helper" + +RSpec.describe RemoteDevelopment::WorkspaceOperations::Create::MainComponentUpdater, feature_category: :workspaces do + include_context 'with remote development shared fixtures' + + let(:input_processed_devfile_name) { 'example.tools-injector-inserted-devfile.yaml' } + let(:input_processed_devfile) { YAML.safe_load(read_devfile(input_processed_devfile_name)).to_h } + let(:expected_processed_devfile_name) { 'example.main-container-updated-devfile.yaml' } + let(:expected_processed_devfile) { YAML.safe_load(read_devfile(expected_processed_devfile_name)).to_h } + + let(:vscode_extensions_gallery_metadata_enabled) { false } + + let(:context) do + { + processed_devfile: input_processed_devfile, + volume_mounts: { + data_volume: { + path: "/projects" + } + }, + vscode_extensions_gallery_metadata: { enabled: vscode_extensions_gallery_metadata_enabled } + } + end + + subject(:returned_value) do + described_class.update(context) # rubocop:disable Rails/SaveBang -- Silly rubocop, this isn't an ActiveRecord object + end + + it 'updates the main component' do + expect(returned_value[:processed_devfile]).to eq(expected_processed_devfile) + end + + context "when vscode_extensions_gallery_metadata Web IDE setting is disabled" do + let(:expected_processed_devfile_name) { 'example.main-container-updated-marketplace-disabled-devfile.yaml' } + let(:vscode_extensions_gallery_metadata_enabled) { false } + + it 'injects the tools injector component' do + expect(returned_value[:processed_devfile]).to eq(expected_processed_devfile) + end + end +end diff --git a/ee/spec/lib/remote_development/workspace_operations/create/main_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/main_spec.rb index 63bb003506c016bb0f6169b3d26f66c34690a00c..9b0ca66e9c9881a64b8bceed4dfda2a649e60d23 100644 --- a/ee/spec/lib/remote_development/workspace_operations/create/main_spec.rb +++ b/ee/spec/lib/remote_development/workspace_operations/create/main_spec.rb @@ -12,9 +12,10 @@ [RemoteDevelopment::WorkspaceOperations::Create::DevfileFlattener, :and_then], [RemoteDevelopment::WorkspaceOperations::Create::PostFlattenDevfileValidator, :and_then], [RemoteDevelopment::WorkspaceOperations::Create::VolumeDefiner, :map], - [RemoteDevelopment::WorkspaceOperations::Create::ToolsComponentInjector, :map], - [RemoteDevelopment::WorkspaceOperations::Create::ProjectClonerComponentInjector, :map], - [RemoteDevelopment::WorkspaceOperations::Create::VolumeComponentInjector, :map], + [RemoteDevelopment::WorkspaceOperations::Create::ToolsInjectorComponentInserter, :map], + [RemoteDevelopment::WorkspaceOperations::Create::MainComponentUpdater, :map], + [RemoteDevelopment::WorkspaceOperations::Create::ProjectClonerComponentInserter, :map], + [RemoteDevelopment::WorkspaceOperations::Create::VolumeComponentInserter, :map], [RemoteDevelopment::WorkspaceOperations::Create::Creator, :and_then] ] end diff --git a/ee/spec/lib/remote_development/workspace_operations/create/post_flatten_devfile_validator_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/post_flatten_devfile_validator_spec.rb index 8a8679c2e8e638cdcac8b0f1cfd24c3c61aedec1..90a2d2adba63486acb6e0346c4f3429c5a94f890 100644 --- a/ee/spec/lib/remote_development/workspace_operations/create/post_flatten_devfile_validator_spec.rb +++ b/ee/spec/lib/remote_development/workspace_operations/create/post_flatten_devfile_validator_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' +require 'fast_spec_helper' RSpec.describe ::RemoteDevelopment::WorkspaceOperations::Create::PostFlattenDevfileValidator, feature_category: :workspaces do include ResultMatchers diff --git a/ee/spec/lib/remote_development/workspace_operations/create/pre_flatten_devfile_validator_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/pre_flatten_devfile_validator_spec.rb index b2cd74cdf36aad627f35ed46a1ecbcc4ba99fbbf..7258d4f6b235889d3296c19c2033fd4753451508 100644 --- a/ee/spec/lib/remote_development/workspace_operations/create/pre_flatten_devfile_validator_spec.rb +++ b/ee/spec/lib/remote_development/workspace_operations/create/pre_flatten_devfile_validator_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' +require 'fast_spec_helper' RSpec.describe ::RemoteDevelopment::WorkspaceOperations::Create::PreFlattenDevfileValidator, feature_category: :workspaces do include ResultMatchers diff --git a/ee/spec/lib/remote_development/workspace_operations/create/project_cloner_component_injector_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/project_cloner_component_inserter_spec.rb similarity index 60% rename from ee/spec/lib/remote_development/workspace_operations/create/project_cloner_component_injector_spec.rb rename to ee/spec/lib/remote_development/workspace_operations/create/project_cloner_component_inserter_spec.rb index a97e873fae90c78e59bea79ed1dc0a5abe949807..1f8b3861005d156f5ca8dfb05824ce0e92b4dd90 100644 --- a/ee/spec/lib/remote_development/workspace_operations/create/project_cloner_component_injector_spec.rb +++ b/ee/spec/lib/remote_development/workspace_operations/create/project_cloner_component_inserter_spec.rb @@ -1,20 +1,21 @@ # frozen_string_literal: true -require "spec_helper" +require "fast_spec_helper" -RSpec.describe RemoteDevelopment::WorkspaceOperations::Create::ProjectClonerComponentInjector, feature_category: :workspaces do +RSpec.describe RemoteDevelopment::WorkspaceOperations::Create::ProjectClonerComponentInserter, feature_category: :workspaces do include_context 'with remote development shared fixtures' - let_it_be(:group) { create(:group, name: "test-group") } - let_it_be(:project) do - create(:project, :in_group, :repository, path: "test-project", namespace: group) + let(:project_path) { "test-project" } + let(:project) do + http_url_to_repo = "#{root_url}test-group/#{project_path}.git" + instance_double("Project", path: project_path, http_url_to_repo: http_url_to_repo) # rubocop:disable RSpec/VerifiedDoubleReference -- We're using the quoted version so we can use fast_spec_helper end - let(:input_processed_devfile_name) { 'example.tools-injected-devfile.yaml' } + let(:input_processed_devfile_name) { 'example.main-container-updated-devfile.yaml' } let(:input_processed_devfile) { YAML.safe_load(read_devfile(input_processed_devfile_name)).to_h } - let(:expected_processed_devfile_name) { 'example.project-cloner-injected-devfile.yaml' } + let(:expected_processed_devfile_name) { 'example.project-cloner-inserted-devfile.yaml' } let(:expected_processed_devfile) { YAML.safe_load(read_devfile(expected_processed_devfile_name)).to_h } - let(:component_name) { "gl-cloner-injector" } + let(:component_name) { "gl-project-cloner" } let(:context) do { params: { @@ -34,7 +35,7 @@ end subject(:returned_value) do - described_class.inject(context) + described_class.insert(context) end it "injects the project cloner component" do diff --git a/ee/spec/lib/remote_development/workspace_operations/create/tools_component_injector_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/tools_injector_component_inserter_spec.rb similarity index 71% rename from ee/spec/lib/remote_development/workspace_operations/create/tools_component_injector_spec.rb rename to ee/spec/lib/remote_development/workspace_operations/create/tools_injector_component_inserter_spec.rb index 2a3c5ccfeef86595c5e4a07b0da8f5cb5f72bf3a..13512974b94523eb6c033fd24d76443ee5163888 100644 --- a/ee/spec/lib/remote_development/workspace_operations/create/tools_component_injector_spec.rb +++ b/ee/spec/lib/remote_development/workspace_operations/create/tools_injector_component_inserter_spec.rb @@ -2,12 +2,12 @@ require "fast_spec_helper" -RSpec.describe RemoteDevelopment::WorkspaceOperations::Create::ToolsComponentInjector, feature_category: :workspaces do +RSpec.describe RemoteDevelopment::WorkspaceOperations::Create::ToolsInjectorComponentInserter, feature_category: :workspaces do include_context 'with remote development shared fixtures' let(:input_processed_devfile_name) { 'example.flattened-devfile.yaml' } let(:input_processed_devfile) { YAML.safe_load(read_devfile(input_processed_devfile_name)).to_h } - let(:expected_processed_devfile_name) { 'example.tools-injected-devfile.yaml' } + let(:expected_processed_devfile_name) { 'example.tools-injector-inserted-devfile.yaml' } let(:expected_processed_devfile) { YAML.safe_load(read_devfile(expected_processed_devfile_name)).to_h } let(:tools_injector_image_from_settings) do "registry.gitlab.com/gitlab-org/remote-development/gitlab-workspaces-tools:2.0.0" @@ -35,10 +35,10 @@ end subject(:returned_value) do - described_class.inject(context) + described_class.insert(context) end - it 'injects the tools injector component' do + it 'inserts the tools injector component' do expect(returned_value[:processed_devfile]).to eq(expected_processed_devfile) end @@ -50,13 +50,4 @@ expect(image_from_processed_devfile).to eq(tools_injector_image_from_settings) end end - - context "when vscode_extensions_gallery_metadata Web IDE setting is disabled" do - let(:expected_processed_devfile_name) { 'example.tools-injected-marketplace-disabled-devfile.yaml' } - let(:vscode_extensions_gallery_metadata_enabled) { false } - - it 'injects the tools injector component' do - expect(returned_value[:processed_devfile]).to eq(expected_processed_devfile) - end - end end diff --git a/ee/spec/lib/remote_development/workspace_operations/create/volume_component_injector_spec.rb b/ee/spec/lib/remote_development/workspace_operations/create/volume_component_inserter_spec.rb similarity index 87% rename from ee/spec/lib/remote_development/workspace_operations/create/volume_component_injector_spec.rb rename to ee/spec/lib/remote_development/workspace_operations/create/volume_component_inserter_spec.rb index 9dfced6ba3362a79f7d9be301193cb332a1f79d3..8ce4736976265c5919a315d6e2eb80fd76f144bb 100644 --- a/ee/spec/lib/remote_development/workspace_operations/create/volume_component_injector_spec.rb +++ b/ee/spec/lib/remote_development/workspace_operations/create/volume_component_inserter_spec.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -require "spec_helper" +require "fast_spec_helper" -RSpec.describe RemoteDevelopment::WorkspaceOperations::Create::VolumeComponentInjector, feature_category: :workspaces do +RSpec.describe RemoteDevelopment::WorkspaceOperations::Create::VolumeComponentInserter, feature_category: :workspaces do include_context 'with remote development shared fixtures' - let(:input_processed_devfile_name) { 'example.project-cloner-injected-devfile.yaml' } + let(:input_processed_devfile_name) { 'example.project-cloner-inserted-devfile.yaml' } let(:input_processed_devfile) { YAML.safe_load(read_devfile(input_processed_devfile_name)).to_h } let(:expected_processed_devfile_name) { 'example.processed-devfile.yaml' } let(:expected_processed_devfile) { YAML.safe_load(read_devfile(expected_processed_devfile_name)).to_h } @@ -24,7 +24,7 @@ end subject(:returned_value) do - described_class.inject(context) + described_class.insert(context) end it "injects the workspace volume component" do diff --git a/ee/spec/support/shared_contexts/remote_development/remote_development_shared_contexts.rb b/ee/spec/support/shared_contexts/remote_development/remote_development_shared_contexts.rb index 86acda26bf142a14c98d6e8642d6203d6d879749..f8a8064ca8e60fa4a3e2bbf90c47c9bfee64729d 100644 --- a/ee/spec/support/shared_contexts/remote_development/remote_development_shared_contexts.rb +++ b/ee/spec/support/shared_contexts/remote_development/remote_development_shared_contexts.rb @@ -845,7 +845,7 @@ def workspace_deployment( ], image: "alpine/git:2.45.2", imagePullPolicy: "Always", - name: "gl-cloner-injector-gl-cloner-injector-command-1", + name: "gl-project-cloner-gl-project-cloner-command-1", resources: { limits: { cpu: "500m", diff --git a/lib/gitlab/fp/rop_helpers.rb b/lib/gitlab/fp/rop_helpers.rb index 5a9db8b9794a5df1b8b54f036257df16b2f4e44a..861d0990050da4c54c01884211d8c4c770c6992d 100644 --- a/lib/gitlab/fp/rop_helpers.rb +++ b/lib/gitlab/fp/rop_helpers.rb @@ -55,7 +55,9 @@ def retrieve_single_public_singleton_method(fp_module_or_class) # @return [Array] def public_singleton_methods_to_ignore # Singleton methods added by other libraries that we need to ignore. - Module.singleton_methods(false) + Class.singleton_methods(false) + Module.singleton_methods(false) + + Class.singleton_methods(false) + + [:_] # NOTE: `_` (from GettextI18nRails) is ignored because we mock it globally in fast_spec_helper end end end diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb index b3004fb40e232335087d9bfc99721927529e6480..4efac06dd71f2b86a13732eab0caf2a5884fe24a 100644 --- a/spec/fast_spec_helper.rb +++ b/spec/fast_spec_helper.rb @@ -43,6 +43,11 @@ def self.spec_requires_and_configuration config.mock_with :rspec do |mocks| mocks.verify_doubled_constant_names = false # Allow mocking of non-lib module/class names from Rails end + + # Mock out the GettextI18nRails `_` method to just pass through the key as the text + config.before do + allow(described_class).to(receive(:_)) { |key| key } + end end Time.zone = 'UTC' # rubocop:disable Gitlab/ChangeTimezone -- allow Time.zone to not be nil in fast_spec_helper, so Time.zone.now works