diff options
Diffstat (limited to 'qa/qa/resource')
-rw-r--r-- | qa/qa/resource/api_fabricator.rb | 2 | ||||
-rw-r--r-- | qa/qa/resource/base.rb | 6 | ||||
-rw-r--r-- | qa/qa/resource/group_base.rb | 6 | ||||
-rw-r--r-- | qa/qa/resource/group_runner.rb | 29 | ||||
-rw-r--r-- | qa/qa/resource/issue.rb | 11 | ||||
-rw-r--r-- | qa/qa/resource/merge_request.rb | 43 | ||||
-rw-r--r-- | qa/qa/resource/project.rb | 40 | ||||
-rw-r--r-- | qa/qa/resource/project_runner.rb | 29 | ||||
-rw-r--r-- | qa/qa/resource/reusable.rb | 163 | ||||
-rw-r--r-- | qa/qa/resource/reusable_collection.rb | 60 | ||||
-rw-r--r-- | qa/qa/resource/reusable_group.rb | 43 | ||||
-rw-r--r-- | qa/qa/resource/reusable_project.rb | 51 | ||||
-rw-r--r-- | qa/qa/resource/runner.rb | 148 | ||||
-rw-r--r-- | qa/qa/resource/runner_base.rb | 129 |
14 files changed, 253 insertions, 507 deletions
diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb index d82109c1d54..44520b04e9a 100644 --- a/qa/qa/resource/api_fabricator.rb +++ b/qa/qa/resource/api_fabricator.rb @@ -104,7 +104,7 @@ module QA raise ResourceNotFoundError, "Resource at #{request.mask_url} could not be found (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}" end - @api_fabrication_http_method = :get # rubocop:disable Gitlab/ModuleWithInstanceVariables + @api_fabrication_http_method ||= :get # rubocop:disable Gitlab/ModuleWithInstanceVariables response end diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb index 00c002cae9c..2abe1904c92 100644 --- a/qa/qa/resource/base.rb +++ b/qa/qa/resource/base.rb @@ -96,11 +96,7 @@ module QA result = yield.tap do fabrication_time = Time.now - start fabrication_http_method = if resource.api_fabrication_http_method == :get || resource.retrieved_from_cache - if include?(Reusable) - "Retrieved for reuse" - else - "Retrieved" - end + "Retrieved" else "Built" end diff --git a/qa/qa/resource/group_base.rb b/qa/qa/resource/group_base.rb index c5b1a4ecea0..5e2a567119d 100644 --- a/qa/qa/resource/group_base.rb +++ b/qa/qa/resource/group_base.rb @@ -16,7 +16,8 @@ module QA :name, :full_path, # Add visibility to enable create private group - :visibility + :visibility, + :shared_with_groups # Get group projects # @@ -140,7 +141,8 @@ module QA :require_two_factor_authentication, :share_with_group_lock, :subgroup_creation_level, - :two_factor_grace_perion + :shared_with_groups, + :two_factor_grace_period # TODO: Add back visibility comparison once https://gitlab.com/gitlab-org/gitlab/-/issues/331252 is fixed # :visibility ) diff --git a/qa/qa/resource/group_runner.rb b/qa/qa/resource/group_runner.rb new file mode 100644 index 00000000000..d7fa26a1d53 --- /dev/null +++ b/qa/qa/resource/group_runner.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module QA + module Resource + class GroupRunner < RunnerBase + attribute :group do + Resource::Group.fabricate_via_api! do |resource| + resource.name = "group-with-ci-cd-#{SecureRandom.hex(8)}" + resource.description = 'Group with CI/CD Pipelines' + end + end + + attribute :token do + group.runners_token + rescue NoValueError + group.reload!.runners_token + end + + private + + def runner(**kwargs) + fail_msg = "Wait for runner '#{name}' to register in group '#{group.name}'" + Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1, message: fail_msg) do + auto_paginated_response(request_url("/runners", **kwargs)).find { |runner| runner[:description] == name } + end + end + end + end +end diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb index 2e18e1d0323..15c2c25757f 100644 --- a/qa/qa/resource/issue.rb +++ b/qa/qa/resource/issue.rb @@ -65,6 +65,10 @@ module QA end end + def api_related_mrs_path + "#{api_get_path}/related_merge_requests" + end + def set_issue_assignees(assignee_ids:) put_body = { assignee_ids: assignee_ids } response = put Runtime::API::Request.new(api_client, api_put_path).url, put_body @@ -79,6 +83,13 @@ module QA QA::Runtime::Logger.debug("Successfully updated issue assignees to #{assignee_ids}") end + # Related merge requests + # + # @return [Array<Hash>] + def related_merge_requests + parse_body(api_get_from(api_related_mrs_path)) + end + protected # Return subset of fields for comparing issues diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb index d1d99393ca2..50ef9538fb0 100644 --- a/qa/qa/resource/merge_request.rb +++ b/qa/qa/resource/merge_request.rb @@ -6,27 +6,27 @@ module QA include ApprovalConfiguration attr_accessor :approval_rules, - :source_branch, - :target_new_branch, - :update_existing_file, - :assignee, - :milestone, - :labels, - :file_name, - :file_content, - :reviewer_ids + :source_branch, + :target_new_branch, + :update_existing_file, + :assignee, + :milestone, + :labels, + :file_name, + :file_content, + :reviewer_ids attr_writer :no_preparation, - :wait_for_merge, - :template + :wait_for_merge, + :template attributes :iid, - :title, - :description, - :merge_when_pipeline_succeeds, - :merge_status, - :state, - :reviewers + :title, + :description, + :merge_when_pipeline_succeeds, + :merge_status, + :state, + :reviewers attribute :project do Project.fabricate_via_api! do |resource| @@ -143,6 +143,13 @@ module QA } end + # Get merge request reviews + # + # @return [Array<Hash>] + def reviews + parse_body(api_get_from(api_reviewers_path)) + end + def merge_via_api! Support::Waiter.wait_until(sleep_interval: 1) do QA::Runtime::Logger.debug("Waiting until merge request with id '#{iid}' can be merged") @@ -179,7 +186,7 @@ module QA def fabricate_large_merge_request @project = Resource::ImportProject.fabricate_via_browser_ui! # Setting the name here, since otherwise some tests will look for an existing file in - # the proejct without ever knowing what is in it. + # the project without ever knowing what is in it. @file_name = "added_file-00000000.txt" @source_branch = "large_merge_request" visit("#{project.web_url}/-/merge_requests/1") diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb index 3cbc002fa86..3f42c6b649e 100644 --- a/qa/qa/resource/project.rb +++ b/qa/qa/resource/project.rb @@ -10,25 +10,25 @@ module QA include ApprovalConfiguration attr_accessor :initialize_with_readme, - :auto_devops_enabled, - :github_personal_access_token, - :github_repository_path, - :gitlab_repository_path, - :personal_namespace + :auto_devops_enabled, + :github_personal_access_token, + :github_repository_path, + :gitlab_repository_path, + :personal_namespace attr_reader :repository_storage attributes :id, - :name, - :path, - :add_name_uuid, - :runners_token, - :visibility, - :template_name, - :import, - :import_status, - :import_error, - :description + :name, + :path, + :add_name_uuid, + :runners_token, + :visibility, + :template_name, + :import, + :import_status, + :import_error, + :description attribute :group do Group.fabricate! do |group| @@ -43,7 +43,7 @@ module QA alias_method :full_path, :path_with_namespace def sandbox_path - return '' if personal_namespace || !group.respond_to?('sandbox') + return '' if personal_namespace || !group.respond_to?(:sandbox) "#{group.sandbox.path}/" end @@ -450,6 +450,14 @@ module QA parse_body(response) end + # Fetch project specific runners + # + # @param [Hash] **kwargs optional query arguments, see: https://docs.gitlab.com/ee/api/runners.html#list-projects-runners + # @return [Array] + def runners(**kwargs) + auto_paginated_response(request_url(api_runners_path, **kwargs)) + end + # Uses the API to wait until a pull mirroring update is successful (pull mirroring is treated as an import) def wait_for_pull_mirroring mirror_succeeded = Support::Retrier.retry_until( diff --git a/qa/qa/resource/project_runner.rb b/qa/qa/resource/project_runner.rb new file mode 100644 index 00000000000..173b17550c7 --- /dev/null +++ b/qa/qa/resource/project_runner.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module QA + module Resource + class ProjectRunner < RunnerBase + attribute :project do + Project.fabricate_via_api! do |resource| + resource.name = 'project-with-ci-cd' + resource.description = 'Project with CI/CD Pipelines' + end + end + + attribute :token do + project.runners_token + rescue NoValueError + project.reload!.runners_token + end + + private + + def runner(**kwargs) + fail_msg = "Wait for runner '#{name}' to register in project '#{project.name}'" + Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1, message: fail_msg) do + project.runners(**kwargs).find { |runner| runner[:description] == name } + end + end + end + end +end diff --git a/qa/qa/resource/reusable.rb b/qa/qa/resource/reusable.rb deleted file mode 100644 index 536f70b50b4..00000000000 --- a/qa/qa/resource/reusable.rb +++ /dev/null @@ -1,163 +0,0 @@ -# frozen_string_literal: true - -module QA - module Resource - # - # This module includes methods that allow resource classes to be reused safely. It should be prepended to a new - # reusable version of an existing resource class. See Resource::Project and ReusableResource::Project for an example. - # Reusable resource classes must also be registered with a resource collection that will manage cleanup. - # - # @example Register a resource class with a collection - # QA::Resource::ReusableCollection.register_resource_classes do |collection| - # QA::Resource::ReusableProject.register(collection) - # end - module Reusable - attr_accessor :reuse, - :reuse_as - - ResourceReuseError = Class.new(RuntimeError) - - def self.prepended(base) - base.extend(ClassMethods) - end - - # Gets an existing resource if it exists and the specified attributes of the resource are valid. - # Creates a new instance of the resource if it does not exist. - # - # @return [String] The URL of the resource. - def fabricate_via_api! - validate_reuse_preconditions - - resource_web_url(api_get) - rescue Errors::ResourceNotFoundError - super - ensure - self.class.resources[reuse_as] ||= { - tests: Set.new, - resource: self - } - - self.class.resources[reuse_as][:attributes] ||= all_attributes.index_with do |attribute_name| - instance_variable_get("@#{attribute_name}") - end - self.class.resources[reuse_as][:tests] << Runtime::Example.location - end - - # Overrides remove_via_api! to log a debug message stating that removal will happen after the suite completes. - # - # @return [nil] - def remove_via_api! - QA::Runtime::Logger.debug("#{self.class.name} - deferring removal until after suite") - end - - # Object comparison - # - # @param [QA::Resource::Base] other - # @return [Boolean] - def ==(other) - self.class <= other.class && comparable == other.comparable - end - - # Confirms that reuse of the resource did not change it in a way that breaks later reuse. - # For example, this should fail if a reusable resource should have a specific name, but the name has been changed. - def validate_reuse - QA::Runtime::Logger.debug(["Validating a #{self.class.name} that was reused as #{reuse_as}", identifier].compact.join(' ')) - - fresh_resource = reference_resource - diff = reuse_validation_diff(fresh_resource) - - if diff.present? - raise ResourceReuseError, <<~ERROR - The reused #{self.class.name} resource does not have the attributes expected. - The following change was found: #{diff}" - The resource's web_url is #{web_url}. - It was used in these tests: #{self.class.resources[reuse_as][:tests].to_a.join(', ')} - ERROR - end - - ensure - fresh_resource.remove_via_api! - end - - private - - # Creates a new resource that can be compared to a reused resource, using the post body of the original. - # Must be implemented by classes that include this module. - def reference_resource - return super if defined?(super) - - raise NotImplementedError - end - - # Confirms that the resource attributes specified in its fabricate_via_api! block will allow it to be reused. - # - # @return [nil] returns nil unless an error is raised - def validate_reuse_preconditions - return unless self.class.resources.key?(reuse_as) - - attributes = unique_identifiers.each_with_object({ proposed: {}, existing: {} }) do |id, attrs| - proposed = public_send(id) - existing = self.class.resources[reuse_as][:resource].public_send(id) - - next if proposed == existing - - attrs[:proposed][id] = proposed - attrs[:existing][id] = existing - end - - unless attributes[:proposed].empty? && attributes[:existing].empty? - raise ResourceReuseError, "Reusable resources must use the same unique identifier(s). " \ - "The #{self.class.name} to be reused as :#{reuse_as} has the identifier(s) #{attributes[:proposed]} " \ - "but it should have #{attributes[:existing]}" - end - end - - # Compares the attributes of the current reused resource with a reference instance. - # - # @return [Hash] any differences between the resources. - def reuse_validation_diff(other) - original, reference = prepare_reuse_validation_diff(other) - - return if original == reference - - diff_values = original.to_a - reference.to_a - diff_values.to_h - end - - # Compares the current reusable resource to a reference instance, ignoring identifying unique attributes that - # had to be changed. - # - # @return [Hash, Hash] the current and reference resource attributes, respectively. - def prepare_reuse_validation_diff(other) - original = self.reload!.comparable - reference = other.reload!.comparable - unique_identifiers.each { |id| reference[id] = original[id] } - [original, reference] - end - - # The attributes of the resource that should be the same whenever a test wants to reuse a resource. Must be - # implemented by classes that include this module. - # - # @return [Array<Symbol>] the attribute names. - def unique_identifiers - return super if defined?(super) - - raise NotImplementedError - end - - module ClassMethods - # Includes the resources created/reused by this class in the specified collection - def register(collection) - collection[self.name] = resources - end - - # The resources created/reused by this resource class. - # - # @return [Hash<Symbol, Hash>] the resources created/reused by this resource class. - def resources - @resources ||= {} - end - end - end - end -end diff --git a/qa/qa/resource/reusable_collection.rb b/qa/qa/resource/reusable_collection.rb deleted file mode 100644 index 99a55800d1c..00000000000 --- a/qa/qa/resource/reusable_collection.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require 'singleton' - -module QA - module Resource - # - # This singleton class collects all reusable resources used by tests and allows operations to be performed on them - # all. For example, verifying their state after tests have run and might have changed them. - # - class ReusableCollection - include Singleton - - attr_accessor :resource_classes - - def initialize - @resource_classes = {} - end - - # Yields each resource in the collection. - # - # @yieldparam [Symbol] reuse_as the name that identifies the resource instance. - # @yieldparam [QA::Resource] reuse_instance the resource. - def each_resource - resource_classes.each_value do |reuse_instances| - reuse_instances.each do |reuse_as, reuse_instance| - yield reuse_as, reuse_instance[:resource] - end - end - end - - class << self - # Removes all created resources that are included in the collection. - def remove_all_via_api! - instance.each_resource do |reuse_as, resource| - next QA::Runtime::Logger.debug("#{resource.class.name} reused as :#{reuse_as} has already been removed.") unless resource.exists? - - if resource.respond_to?(:marked_for_deletion?) && resource.marked_for_deletion? - next QA::Runtime::Logger.debug("#{resource.class.name} reused as :#{reuse_as} is already scheduled to be removed.") - end - - resource.method(:remove_via_api!).super_method.call - end - end - - # Validates the reuse of each resource as defined by the resource class of each resource in the collection. - def validate_resource_reuse - instance.each_resource { |_, resource| resource.validate_reuse } - end - - # Yields the collection of resources to allow resource classes to register themselves with the collection. - # - # @yieldparam [Hash] resource_classes the resource classes in the collection. - def register_resource_classes - yield instance.resource_classes - end - end - end - end -end diff --git a/qa/qa/resource/reusable_group.rb b/qa/qa/resource/reusable_group.rb deleted file mode 100644 index 05ff38249f6..00000000000 --- a/qa/qa/resource/reusable_group.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -module QA - module Resource - class ReusableGroup < Group - prepend Reusable - - def initialize - super - - @name = @path = QA::Runtime::Env.reusable_group_path - @description = "QA reusable group" - @reuse_as = :default_group - end - - private - - # Creates a new group that can be compared to a reused group, using the attributes of the original. Attributes that - # must be unique (path and name) are replaced with new unique values. - # - # @return [QA::Resource] a new instance of Resource::ReusableGroup that should be a copy of the original resource - def reference_resource - attributes = self.class.resources[reuse_as][:attributes] - name = "ref#{SecureRandom.hex(8)}_#{attributes.delete(:path)}"[0...MAX_NAME_LENGTH] - - Group.fabricate_via_api! do |resource| - self.class.resources[reuse_as][:attributes].each do |attribute_name, attribute_value| - resource.instance_variable_set("@#{attribute_name}", attribute_value) if attribute_value - end - resource.path = name - resource.name = name - end - end - - # The attributes of the resource that should be the same whenever a test wants to reuse a group. - # - # @return [Array<Symbol>] the attribute names. - def unique_identifiers - [:name, :path] - end - end - end -end diff --git a/qa/qa/resource/reusable_project.rb b/qa/qa/resource/reusable_project.rb deleted file mode 100644 index 8a12c25b6f0..00000000000 --- a/qa/qa/resource/reusable_project.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -module QA - module Resource - class ReusableProject < Project - prepend Reusable - - attribute :group do - ReusableGroup.fabricate_via_api! do |resource| - resource.api_client = api_client - end - end - - def initialize - super - - @add_name_uuid = false - @name = @path = QA::Runtime::Env.reusable_project_path - @reuse_as = :default_project - @initialize_with_readme = true - end - - private - - # Creates a new project that can be compared to a reused project, using the attributes of the original. Attributes - # that must be unique (path and name) are replaced with new unique values. - # - # @return [QA::Resource] a new instance of Resource::ReusableProject that should be a copy of the original resource - def reference_resource - attributes = self.class.resources[reuse_as][:attributes] - name = "reference_resource_#{SecureRandom.hex(8)}_for_#{attributes.delete(:name)}" - - Project.fabricate_via_api! do |project| - self.class.resources[reuse_as][:attributes].each do |attribute_name, attribute_value| - project.instance_variable_set("@#{attribute_name}", attribute_value) if attribute_value - end - project.name = name - project.path = name - project.path_with_namespace = "#{project.group.full_path}/#{project.name}" - end - end - - # The attributes of the resource that should be the same whenever a test wants to reuse a project. - # - # @return [Array<Symbol>] the attribute names. - def unique_identifiers - [:name, :path] - end - end - end -end diff --git a/qa/qa/resource/runner.rb b/qa/qa/resource/runner.rb deleted file mode 100644 index 3c74d8de21a..00000000000 --- a/qa/qa/resource/runner.rb +++ /dev/null @@ -1,148 +0,0 @@ -# frozen_string_literal: true - -module QA - module Resource - class Runner < Base - attributes :id, - :active, - :paused, - :runner_type, - :online, - :status, - :ip_address, - :token, - :tags, - :config, - :run_untagged, - :name, # This attribute == runner[:description] - :image, - :executor, - :executor_image - - attribute :project do - Project.fabricate_via_api! do |resource| - resource.name = 'project-with-ci-cd' - resource.description = 'Project with CI/CD Pipelines' - end - end - - def initialize - @tags = nil - @config = nil - @run_untagged = nil - @name = "qa-runner-#{SecureRandom.hex(4)}" - @image = 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine' - @executor = :shell - @executor_image = 'registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7' - end - - # Initially we only support fabricate - # via API - def fabricate! - fabricate_via_api! - end - - # Start container and register runner - # Fetch via API and populate attributes - # - def fabricate_via_api! - start_container_and_register - populate_runner_attributes - end - - def remove_via_api! - super - ensure - @docker_container.remove! - end - - def reload! - populate_runner_attributes - end - - def api_delete_path - "/runners/#{id}" - end - - def api_get_path - "/runners" - end - - def api_post_path - "/runners" - end - - def api_post_body; end - - def not_found_by_tags? - url = "#{api_get_path}?tag_list=#{tags.compact.join(',')}" - auto_paginated_response(request_url(url)).empty? - end - - def runners_list - runners_list = nil - url = tags ? "#{api_get_path}?tag_list=#{tags.compact.join(',')}" : api_get_path - Runtime::Logger.info('Looking for list of runners via API...') - Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1) do - runners_list = auto_paginated_response(request_url(url)) - runners_list.present? - end - - runners_list - end - - def wait_until_online - Runtime::Logger.info('Waiting for runner to come online...') - Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1) do - this_runner[:status] == 'online' - end - end - - def restart - Runtime::Logger.info("Restarting runner container #{name}...") - @docker_container.restart - wait_until_online - end - - private - - def start_container_and_register - @docker_container = Service::DockerRun::GitlabRunner.new(name).tap do |runner| - Support::Retrier.retry_on_exception(sleep_interval: 5) do - runner.pull - end - - runner.token = @token ||= project.runners_token - runner.address = Runtime::Scenario.gitlab_address - runner.tags = tags if tags - runner.image = image - runner.config = config if config - runner.executor = executor - runner.executor_image = executor_image if executor == :docker - runner.run_untagged = run_untagged if run_untagged - runner.register! - end - end - - def this_runner - runner = nil - Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1) do - runner = runners_list.find { |runner| runner[:description] == name } - !runner.nil? - end - runner - end - - def populate_runner_attributes - runner = this_runner - @id = runner[:id] - @active = runner[:active] - @paused = runner[:paused] - @runner_type = runner[:typed] - @online = runner[:online] - @status = runner[:status] - @ip_address = runner[:ip_address] - end - end - end -end diff --git a/qa/qa/resource/runner_base.rb b/qa/qa/resource/runner_base.rb new file mode 100644 index 00000000000..7580aa108c9 --- /dev/null +++ b/qa/qa/resource/runner_base.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +module QA + module Resource + class RunnerBase < Base + attr_accessor :run_untagged, + :image, + :executor, + :executor_image, + :tags, + :config + + attributes :id, + :active, + :paused, + :runner_type, + :online, + :status, + :ip_address, + :description, + :name, + :is_shared, + :contacted_at, + :platform, + :architecture, + :projects, + :revision, + :tag_list, + :version, + :access_level, + :maximum_timeout + + def initialize + @tags = nil + @config = nil + @run_untagged = nil + @name = "qa-runner-#{SecureRandom.hex(4)}" + @image = 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine' + @executor = :shell + @executor_image = 'registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7' + end + + # Initially we only support fabricate via API + def fabricate! + fabricate_via_api! + end + + # Start container and register runner + # Fetch via API and populate attributes + # + def fabricate_via_api! + api_get + rescue NoValueError + # Start container on initial fabrication and populate all attributes once id is known + # see: https://docs.gitlab.com/ee/api/runners.html#get-runners-details + start_container_and_register + api_get + end + + def remove_via_api! + super + ensure + @docker_container.remove! + @docker_container = nil + end + + def api_get_path + "/runners/#{id}" + end + + def api_post_path + "/runners" + end + + def api_delete_path + api_get_path + end + + def api_post_body; end + + def wait_until_online + Runtime::Logger.info('Waiting for runner to come online...') + Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1) do + reload! && status == 'online' + end + end + + def restart + Runtime::Logger.info("Restarting runner container #{name}...") + @docker_container.restart + wait_until_online + end + + private + + def start_container_and_register + @docker_container ||= Service::DockerRun::GitlabRunner.new(name).tap do |runner| + Support::Retrier.retry_on_exception(sleep_interval: 5) do + runner.pull + end + + runner.token = token + runner.address = Runtime::Scenario.gitlab_address + runner.tags = tags if tags + runner.image = image + runner.config = config if config + runner.executor = executor + runner.executor_image = executor_image if executor == :docker + runner.run_untagged = run_untagged if run_untagged + runner.register! + end + populate_initial_id + rescue StandardError => e + @docker_container&.remove! + raise(e) + end + + def populate_initial_id + tag_list = tags ? { tag_list: tags.compact.join(',') } : {} + runner = runner(**tag_list) + @id = runner[:id] + end + + def runner(**kwargs) + raise("Not implemented!") + end + end + end +end |