From 74c4785b31e7fa3ce43a8df5da15150830c287b2 Mon Sep 17 00:00:00 2001 From: Vitalii Chulak Date: Sun, 25 May 2025 20:48:38 +0300 Subject: [PATCH] RHELMISC-4745: Add ability to bring up previous session Signed-off-by: Vitalii Chulak --- bin/auto_hck | 9 +- lib/all.rb | 1 + lib/cli.rb | 436 ++++++++++++---------- lib/engines/hcktest/hcktest.rb | 20 +- lib/project.rb | 34 +- lib/session.rb | 26 ++ lib/setupmanagers/hckclient.rb | 9 +- lib/setupmanagers/hckstudio.rb | 2 + lib/setupmanagers/physhck/physhck.rb | 2 +- lib/setupmanagers/qemuhck/qemu_machine.rb | 9 +- lib/setupmanagers/qemuhck/qemuhck.rb | 2 +- 11 files changed, 324 insertions(+), 226 deletions(-) create mode 100644 lib/session.rb diff --git a/bin/auto_hck b/bin/auto_hck index f70632c1..375e49a4 100755 --- a/bin/auto_hck +++ b/bin/auto_hck @@ -9,6 +9,13 @@ module AutoHCK run do cli = CLI.new cli.parse(ARGV) + session_path = cli.test.latest_session ? "#{Config.read['workspace_path']}/latest" : cli.test.session + + session = if session_path + Session.load(session_path, cli.common.workspace_path) + else + Session.new(cli: cli) + end ENV.store 'LC_ALL', 'en_US.UTF-8' @@ -18,7 +25,7 @@ module AutoHCK Thread.report_on_exception = false ResourceScope.open do |scope| - @project = Project.new(scope, cli) + @project = Project.new(scope, session) Trap.project = @project @project.run if @project.prepare rescue StandardError => e diff --git a/lib/all.rb b/lib/all.rb index 7261a673..099ca6ab 100644 --- a/lib/all.rb +++ b/lib/all.rb @@ -61,6 +61,7 @@ module AutoHCK autoload_relative :PhysHCK, 'setupmanagers/physhck/physhck' autoload_relative :Playlist, 'engines/hcktest/playlist' autoload_relative :Project, 'project' + autoload_relative :Session, 'session' autoload_relative :QemuHCK, 'setupmanagers/qemuhck/qemuhck' autoload_relative :QemuHCKError, 'setupmanagers/qemuhck/exceptions' autoload_relative :QemuMachine, 'setupmanagers/qemuhck/qemu_machine' diff --git a/lib/cli.rb b/lib/cli.rb index be890ffa..5ae9b4de 100644 --- a/lib/cli.rb +++ b/lib/cli.rb @@ -1,252 +1,278 @@ +# typed: true # frozen_string_literal: true # AutoHCK module module AutoHCK - # class CLI - class CLI - attr_reader :common, :install, :test, :mode + # class CommonOptions + class CommonOptions < T::Struct + include T::Sig + + prop :verbose, T::Boolean, default: false + prop :config, T.nilable(String) + prop :client_world_net, T::Boolean, default: false + prop :id, Integer, default: 2 + prop :share_on_host_path, T.nilable(String) + prop :workspace_path, T.nilable(String) + prop :client_ctrl_net_dev, T.nilable(String) + + def create_parser(sub_parser) + OptionParser.new do |parser| + parser.banner = 'Usage: auto_hck.rb [common options] [command options]' + parser.separator '' + define_options(parser) + parser.on_tail('-h', '--help', 'Show this message') do + puts parser + sub_parser&.each_value do |v| + puts v + end + exit + end + end + end - def initialize - @common = CommonOptions.new - @test = TestOptions.new - @install = InstallOptions.new + # rubocop:disable Metrics/MethodLength + def define_options(parser) + parser.on('--share-on-host-path ', String, + 'For using Transfer Network specify the directory to share on host machine') do |share_on_host_path| + @share_on_host_path = share_on_host_path + end - @sub_parser = { - 'test' => @test.create_parser, - 'install' => @install.create_parser - } + parser.on('--verbose', TrueClass, + 'Enable verbose logging', + &method(:verbose=)) + + parser.on('--config ', String, + 'Path to custom override.json file', + &method(:config=)) + + parser.on('--client_world_net', TrueClass, + 'Attach world bridge to clients VM', + &method(:client_world_net=)) + + parser.on('--client-ctrl-net-dev ', String, + 'Client VM control network device (make sure that driver is installed)', + &method(:client_ctrl_net_dev=)) + + parser.on('--id ', Integer, + 'Set ID for AutoHCK run', + &method(:id=)) - @parser = @common.create_parser(@sub_parser) + parser.on('-v', '--version', + 'Display version information and exit') do + puts "AutoHCK Version: #{AutoHCK::VERSION}" + exit + end + + parser.on('-w ', String, + 'Internal use only', + &method(:workspace_path=)) end + end - # class CommonOptions - class CommonOptions - attr_accessor :verbose, :config, :client_world_net, :id, :share_on_host_path, :workspace_path, - :client_ctrl_net_dev - - def create_parser(sub_parser) - OptionParser.new do |parser| - parser.banner = 'Usage: auto_hck.rb [common options] [command options]' - parser.separator '' - define_options(parser) - parser.on_tail('-h', '--help', 'Show this message') do - puts parser - sub_parser&.each_value do |v| - puts v - end - exit - end + # class TestOptions + class TestOptions < T::Struct + include T::Sig + + prop :platform, T.nilable(String) + prop :drivers, T::Array[String], default: [] + prop :driver_path, T.nilable(String) + prop :commit, T.nilable(String) + prop :svvp, T::Boolean, default: false + prop :dump, T::Boolean, default: false + prop :gthb_context_prefix, T.nilable(String) + prop :gthb_context_suffix, T.nilable(String) + prop :playlist, T.nilable(String) + prop :select_test_names, T.nilable(String) + prop :reject_test_names, T.nilable(String) + prop :reject_report_sections, T::Array[String], default: [] + prop :boot_device, T.nilable(String) + prop :allow_test_duplication, T::Boolean, default: false + prop :manual, T::Boolean, default: false + prop :package_with_playlist, T::Boolean, default: false + prop :enable_vbs, T::Boolean, default: false + prop :session, T.nilable(String) + prop :latest_session, T::Boolean, default: false + + def create_parser + OptionParser.new do |parser| + parser.banner = 'Usage: auto_hck.rb test [test options]' + parser.separator '' + define_options(parser) + parser.on_tail('-h', '--help', 'Show this message') do + puts parser + exit end end + end - # rubocop:disable Metrics/AbcSize,Metrics/MethodLength - def define_options(parser) - @verbose = false - @config = nil - @client_world_net = false - @id = 2 - @share_on_host_path = nil - - parser.on('--share-on-host-path ', String, - 'For using Transfer Network specify the directory to share on host machine') do |share_on_host_path| - @share_on_host_path = share_on_host_path - end + def define_options(parser) # rubocop:disable Metrics/AbcSize + @reject_report_sections = [] - parser.on('--verbose', TrueClass, - 'Enable verbose logging', - &method(:verbose=)) + parser.on('-p', '--platform ', String, + 'Platform for run test', + &method(:platform=)) - parser.on('--config ', String, - 'Path to custom override.json file', - &method(:config=)) + parser.on('-d', '--drivers ', Array, + 'List of driver for run test', + &method(:drivers=)) - parser.on('--client_world_net', TrueClass, - 'Attach world bridge to clients VM', - &method(:client_world_net=)) + parser.on('--driver-path ', String, + 'Path to the location of the driver wanted to be tested', + &method(:driver_path=)) - parser.on('--client-ctrl-net-dev ', String, - 'Client VM control network device (make sure that driver is installed)', - &method(:client_ctrl_net_dev=)) + parser.on('-c', '--commit ', String, + 'Commit hash for CI status update', + &method(:commit=)) - parser.on('--id ', Integer, - 'Set ID for AutoHCK run', - &method(:id=)) + parser.on('--svvp', TrueClass, + 'Run SVVP tests for specified platform instead of driver tests', + &method(:svvp=)) - parser.on('-v', '--version', - 'Display version information and exit') do - puts "AutoHCK Version: #{AutoHCK::VERSION}" - exit - end + parser.on('--dump', TrueClass, + 'Create machines snapshots and generate scripts for run it manualy', + &method(:dump=)) - parser.on('-w ', String, - 'Internal use only', - &method(:workspace_path=)) - end - # rubocop:enable Metrics/AbcSize,Metrics/MethodLength - end + parser.on('--gthb_context_prefix ', String, + 'Add custom prefix for GitHub CI results context', + &method(:gthb_context_prefix=)) - # class TestOptions - class TestOptions - attr_accessor :platform, :drivers, :driver_path, :commit, :svvp, :dump, - :gthb_context_prefix, :gthb_context_suffix, :playlist, :select_test_names, - :reject_test_names, :reject_report_sections, :boot_device, - :allow_test_duplication, :manual, :package_with_playlist, :enable_vbs - - def create_parser - OptionParser.new do |parser| - parser.banner = 'Usage: auto_hck.rb test [test options]' - parser.separator '' - define_options(parser) - parser.on_tail('-h', '--help', 'Show this message') do - puts parser - exit - end - end - end + parser.on('--gthb_context_suffix ', String, + 'Add custom suffix for GitHub CI results context', + &method(:gthb_context_suffix=)) - # rubocop:disable Metrics/AbcSize, Metrics/MethodLength - def define_options(parser) - @reject_report_sections = [] - @svvp = false - @enable_vbs = false - - parser.on('-p', '--platform ', String, - 'Platform for run test', - &method(:platform=)) - - parser.on('-d', '--drivers ', Array, - 'List of driver for run test', - &method(:drivers=)) - - parser.on('--driver-path ', String, - 'Path to the location of the driver wanted to be tested', - &method(:driver_path=)) - - parser.on('-c', '--commit ', String, - 'Commit hash for CI status update', - &method(:commit=)) - - parser.on('--svvp', TrueClass, - 'Run SVVP tests for specified platform instead of driver tests', - &method(:svvp=)) - - parser.on('--dump', TrueClass, - 'Create machines snapshots and generate scripts for run it manualy', - &method(:dump=)) - - parser.on('--gthb_context_prefix ', String, - 'Add custom prefix for GitHub CI results context', - &method(:gthb_context_prefix=)) - - parser.on('--gthb_context_suffix ', String, - 'Add custom suffix for GitHub CI results context', - &method(:gthb_context_suffix=)) - - parser.on('--playlist ', String, - 'Use custom Microsoft XML playlist', - &method(:playlist=)) - - parser.on('--select-test-names ', String, - 'Use custom user text playlist', - &method(:select_test_names=)) - - parser.on('--reject-test-names ', String, - 'Use custom CI text ignore list', - &method(:reject_test_names=)) - - parser.on('--enable-vbs', TrueClass, - 'Enable VBS state for clients', - &method(:enable_vbs=)) - - parser.on('--reject-report-sections ', Array, - 'List of section to reject from HTML results', - '(use "--reject-report-sections=help" to list sections)') do |reject_report_sections| - if reject_report_sections.first == 'help' - puts Tests::RESULTS_REPORT_SECTIONS.join("\n") - exit - end + parser.on('--playlist ', String, + 'Use custom Microsoft XML playlist', + &method(:playlist=)) - extra_keys = reject_report_sections - Tests::RESULTS_REPORT_SECTIONS + parser.on('--select-test-names ', String, + 'Use custom user text playlist', + &method(:select_test_names=)) - raise(AutoHCKError, "Unknown report sections: #{extra_keys.join(', ')}.") unless extra_keys.empty? + parser.on('--reject-test-names ', String, + 'Use custom CI text ignore list', + &method(:reject_test_names=)) - @reject_report_sections = reject_report_sections + parser.on('--reject-report-sections ', Array, + 'List of section to reject from HTML results', + '(use "--reject-report-sections=help" to list sections)') do |reject_report_sections| + if reject_report_sections.first == 'help' + puts Tests::RESULTS_REPORT_SECTIONS.join("\n") + exit end - parser.on('--boot-device ', String, - 'VM boot device', - &method(:boot_device=)) - - parser.on('--allow-test-duplication', TrueClass, - 'Allow run the same test several times.', - 'Works only with custom user text playlist.', - 'Test results table can be broken. (experimental)', - &method(:allow_test_duplication=)) + extra_keys = reject_report_sections - Tests::RESULTS_REPORT_SECTIONS - parser.on('--manual', TrueClass, - 'Run AutoHCK in manual mode', - &method(:manual=)) + raise(AutoHCKError, "Unknown report sections: #{extra_keys.join(', ')}.") unless extra_keys.empty? - parser.on('--package-with-playlist', TrueClass, - 'Load playlist into HLKX project package', - &method(:package_with_playlist=)) + @reject_report_sections = reject_report_sections end - # rubocop:enable Metrics/AbcSize, Metrics/MethodLength + + parser.on('--boot-device ', String, + 'VM boot device', + &method(:boot_device=)) + + parser.on('--allow-test-duplication', TrueClass, + 'Allow run the same test several times.', + 'Works only with custom user text playlist.', + 'Test results table can be broken. (experimental)', + &method(:allow_test_duplication=)) + + parser.on('--manual', TrueClass, + 'Run AutoHCK in manual mode', + &method(:manual=)) + + parser.on('--package-with-playlist', TrueClass, + 'Load playlist into HLKX project package', + &method(:package_with_playlist=)) + + parser.on('--session ', String, + 'Load session from workspace', + &method(:session=)) + + parser.on('--latest-session', TrueClass, + 'Load previous session', + &method(:latest_session=)) end + # rubocop:enable Metrics/MethodLength + end - # class InstallOptions - class InstallOptions - attr_accessor :platform, :force, :skip_client, :drivers, :driver_path, :debug - - def create_parser - OptionParser.new do |parser| - parser.banner = 'Usage: auto_hck.rb install [install options]' - parser.separator '' - define_options(parser) - parser.on_tail('-h', '--help', 'Show this message') do - puts parser - exit - end + # class InstallOptions + class InstallOptions < T::Struct + include T::Sig + + prop :platform, T.nilable(String) + prop :force, T::Boolean, default: false + prop :skip_client, T::Boolean, default: false + prop :drivers, T::Array[String], default: [] + prop :driver_path, T.nilable(String) + prop :debug, T::Boolean, default: false + + def create_parser + OptionParser.new do |parser| + parser.banner = 'Usage: auto_hck.rb install [install options]' + parser.separator '' + define_options(parser) + parser.on_tail('-h', '--help', 'Show this message') do + puts parser + exit end end + end - # rubocop:disable Metrics/MethodLength - def define_options(parser) - @force = false - @skip_client = false - @drivers = [] - @debug = false + def define_options(parser) + parser.on('--debug', TrueClass, 'Enable debug mode', + &method(:debug=)) - parser.on('--debug', TrueClass, 'Enable debug mode', - &method(:debug=)) + parser.on('-p', '--platform ', String, + 'Install VM for specified platform', + &method(:platform=)) - parser.on('-p', '--platform ', String, - 'Install VM for specified platform', - &method(:platform=)) + parser.on('-f', '--force', TrueClass, + 'Install all VM, replace studio if exist', + &method(:force=)) - parser.on('-f', '--force', TrueClass, - 'Install all VM, replace studio if exist', - &method(:force=)) + parser.on('--skip_client', TrueClass, + 'Skip client images installation', + &method(:skip_client=)) - parser.on('--skip_client', TrueClass, - 'Skip client images installation', - &method(:skip_client=)) + parser.on('-d', '--drivers ', Array, + 'List of driver attach in install', + &method(:drivers=)) - parser.on('-d', '--drivers ', Array, - 'List of driver attach in install', - &method(:drivers=)) + parser.on('--driver-path ', String, + 'Path to the location of the driver wanted to be installed', + &method(:driver_path=)) + end + end - parser.on('--driver-path ', String, - 'Path to the location of the driver wanted to be installed', - &method(:driver_path=)) - end - # rubocop:enable Metrics/MethodLength + # class CLI + class CLI < T::Struct + extend AutoHCK::Models::JsonHelper + extend T::Sig + + prop :test, TestOptions, factory: -> { TestOptions.new } + prop :common, CommonOptions, factory: -> { CommonOptions.new } + prop :install, InstallOptions, factory: -> { InstallOptions.new } + prop :mode, T.nilable(String), default: nil + + sig { returns(T::Hash[String, OptionParser]) } + def sub_parser + { + 'test' => test.create_parser, + 'install' => install.create_parser + } + end + + sig { returns(OptionParser) } + def parser + common.create_parser(sub_parser) end + sig { params(args: T::Array[String]).returns(T::Array[String]) } def parse(args) - left = @parser.order(args) + left = parser.order(args) @mode = left.shift - @sub_parser[@mode]&.order!(left) unless @mode.nil? + sub_parser[@mode]&.order!(left) unless @mode.nil? end end end diff --git a/lib/engines/hcktest/hcktest.rb b/lib/engines/hcktest/hcktest.rb index fd471e24..8550efd8 100644 --- a/lib/engines/hcktest/hcktest.rb +++ b/lib/engines/hcktest/hcktest.rb @@ -169,7 +169,7 @@ def run_clients_post_start_host_commands end def configure_and_synchronize_clients - run_only = @project.options.test.manual && @project.options.test.driver_path.nil? + run_only = @project.restored? || (@project.options.test.manual && @project.options.test.driver_path.nil?) @clients.each_value do |client| client.configure(run_only:) @@ -186,6 +186,7 @@ def configure_setup_and_synchronize configure_and_synchronize_clients @studio.keep_snapshot @clients.each_value(&:keep_snapshot) + @project.save_session unless @project.restored? end def run_clients_and_configure_setup(scope, **opts) @@ -254,9 +255,19 @@ def prepare_tests @test_list = @tests.update_tests(log: true) end + def init_vm_options + return {} unless @project.restored? + + { + boot_from_snapshot: true, + create_snapshot: false, + configure: false + } + end + def auto_run ResourceScope.open do |scope| - run_studio scope + run_studio(scope, **init_vm_options) sleep 5 until @studio.up? run_tests_without_config @@ -268,7 +279,7 @@ def auto_run def run_tests_without_config ResourceScope.open do |scope| - run_clients_and_configure_setup scope + run_clients_and_configure_setup(scope, **init_vm_options) prepare_tests @logger.info('Client ready, running basic tests') @@ -307,7 +318,7 @@ def group_tests_by_config end def run - upload_driver_package unless @driver_path.nil? + upload_driver_package unless @driver_path.nil? || @project.restored? if @project.options.test.dump @project.logger.info('AutoHCK started in dump only mode') @@ -315,7 +326,6 @@ def run dump_run @project.logger.info("Find all scripts in folder: #{@project.workspace_path}") - @project.logger.warn('Dump mode is only for basic tests.') @project.logger.warn('For specific configurations (e.g., Secure Boot tests), update scripts manually.') else auto_run diff --git a/lib/project.rb b/lib/project.rb index b93c2ac7..5031147c 100644 --- a/lib/project.rb +++ b/lib/project.rb @@ -7,20 +7,21 @@ class Project include Helper JUNIT_RESULT = 'junit.xml' - attr_reader :config, :logger, :timestamp, :setup_manager, :engine, :id, + attr_reader :config, :logger, :timestamp, :setup_manager, :engine, :workspace_path, :github, :result_uploader, :engine_tag, :engine_platform, :engine_type, :options, :extra_sw_manager, :run_terminated, :engine_name, :string_log - def initialize(scope, options) + def initialize(scope, session) @scope = scope - @options = options + @options = session.cli + @session = session + init_timestamp - Json.update_json_override(options.common.config) unless options.common.config.nil? - init_multilog(options.common.verbose) + Json.update_json_override(@options.common.config) unless @options.common.config.nil? + init_multilog(@options.common.verbose) init_class_variables init_workspace - @id = options.common.id # ResultUploader must be initialized before adding project to scope # Project uses ResultUploader on close, so ResultUploader must exist # when project is closed @@ -162,7 +163,11 @@ def init_workspace @workspace_path = @options.common.workspace_path return end + restored? ? restore_workspace : create_workspace + @setup_manager_type&.enter @workspace_path + end + def create_workspace @workspace_path = File.join(@config['workspace_path'], @engine_name, @engine_tag, @@ -181,7 +186,20 @@ def init_workspace end File.symlink(@workspace_path, "#{@config['workspace_path']}/latest") - @setup_manager_type&.enter @workspace_path + end + + def restore_workspace + @workspace_path = @options.test.session + + @logger.info("Loading workspace from #{@workspace_path}") + end + + def save_session + @session.save(@workspace_path, @logger) + end + + def restored? + !!@options.test.session end def handle_cancel @@ -193,6 +211,8 @@ def handle_error end def generate_junit + return if restored? + results_file = "#{@workspace_path}/#{JUNIT_RESULT}" @junit.generate(results_file) diff --git a/lib/session.rb b/lib/session.rb new file mode 100644 index 00000000..6cb428b4 --- /dev/null +++ b/lib/session.rb @@ -0,0 +1,26 @@ +# typed: true +# frozen_string_literal: true + +module AutoHCK + class Session < T::Struct + extend T::Sig + extend Models::JsonHelper + + prop :cli, CLI + + sig { params(workspace_path: String, logger: AutoHCK::MultiLogger).void } + def save(workspace_path, logger) + File.write("#{workspace_path}/session.json", serialize.to_json) + logger.info("Session saved to #{workspace_path}/session.json") + end + + sig { params(session_path: String, workspace_path: T.nilable(String)).returns(Session) } + def self.load(session_path, workspace_path) + session = Session.from_json_file("#{session_path}/session.json") + session.cli.common.workspace_path = workspace_path + session.cli.test.session = session_path + session.cli.test.manual = true + session + end + end +end diff --git a/lib/setupmanagers/hckclient.rb b/lib/setupmanagers/hckclient.rb index c4465c05..41a5b5f5 100644 --- a/lib/setupmanagers/hckclient.rb +++ b/lib/setupmanagers/hckclient.rb @@ -34,6 +34,10 @@ def keep_snapshot @runner.keep_snapshot end + def search_target + @target = Targets.new(self, @project, @tools, pool).search_target + end + def add_target_to_project @target = Targets.new(self, @project, @tools, pool).add_target_to_project end @@ -157,8 +161,9 @@ def prepare_machine def configure(run_only: false) @tools = @studio.tools @cooldown_thread = Thread.new do - unless pool == @project.engine_tag - return_when_client_up + if @project.restored? || pool != @project.engine_tag + return_when_client_up unless @project.restored? + search_target if run_only @logger.info("Preparing client skipped #{@name}...") diff --git a/lib/setupmanagers/hckstudio.rb b/lib/setupmanagers/hckstudio.rb index 162f74e6..fc42b24f 100644 --- a/lib/setupmanagers/hckstudio.rb +++ b/lib/setupmanagers/hckstudio.rb @@ -80,6 +80,8 @@ def configure(clients) connect verify_tools update_filters + return if @project.restored? + create_pool create_project end diff --git a/lib/setupmanagers/physhck/physhck.rb b/lib/setupmanagers/physhck/physhck.rb index af20c637..fea74cd7 100644 --- a/lib/setupmanagers/physhck/physhck.rb +++ b/lib/setupmanagers/physhck/physhck.rb @@ -34,7 +34,7 @@ def initialize(project) @logger = project.logger @platform = project.engine_platform @setup = find_setup - @id = project.id + @id = project.options.common.id @kit = @setup['kit'] end diff --git a/lib/setupmanagers/qemuhck/qemu_machine.rb b/lib/setupmanagers/qemuhck/qemu_machine.rb index 67bd38f6..67884d1f 100644 --- a/lib/setupmanagers/qemuhck/qemu_machine.rb +++ b/lib/setupmanagers/qemuhck/qemu_machine.rb @@ -154,7 +154,8 @@ def close boot_from_snapshot: false, attach_iso_list: [], dump_only: false, - secure: false + secure: false, + configure: true }.freeze MACHINE_JSON = 'lib/setupmanagers/qemuhck/machine.json' @@ -188,7 +189,6 @@ def define_local_variables @drive_cache_options = [] @define_variables = {} @run_opts = {} - @configured = false end sig { returns(T::Array[Models::CommandInfo]) } @@ -690,13 +690,14 @@ def run(scope, run_opts = nil) process_device_commands normalize_lists + @configure = @run_opts[:configure] if @run_opts.key?(:configure) if @run_opts[:dump_only] dump_commands else - unless @configured + if @configure run_config_commands - @configured = true + @configure = false end scope.transaction do |tmp_scope| diff --git a/lib/setupmanagers/qemuhck/qemuhck.rb b/lib/setupmanagers/qemuhck/qemuhck.rb index 651e44b0..261ff8e9 100644 --- a/lib/setupmanagers/qemuhck/qemuhck.rb +++ b/lib/setupmanagers/qemuhck/qemuhck.rb @@ -27,7 +27,7 @@ def initialize(project) def initialize_project(project) @project = project - @id = project.id + @id = project.options.common.id @workspace_path = project.workspace_path @logger = project.logger