Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"install_engine": "hckinstall",
"config_engine": "config_manager",
"functest_engine": "functest",
"merge_engine": "hlkxmerge",
"time_out": "9"
}
1 change: 1 addition & 0 deletions lib/all.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ module AutoHCK
autoload_relative :HCKInstall, 'engines/hckinstall/hckinstall'
autoload_relative :HCKStudio, 'setupmanagers/hckstudio'
autoload_relative :HCKTest, 'engines/hcktest/hcktest'
autoload_relative :HLKXMerge, 'engines/hlkxmerge/hlkxmerge'
autoload_relative :Helper, 'helper'
autoload_relative :InvalidConfigFile, 'exceptions'
autoload_relative :InvalidEngineTypeError, 'engines/exceptions'
Expand Down
38 changes: 37 additions & 1 deletion lib/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -334,21 +334,57 @@ def define_options(parser)
end
end

class CliMergeOptions < T::Struct
extend T::Sig

prop :platform, T.nilable(String)
prop :packages, T::Array[String], default: []
prop :output_file, T.nilable(String)

def create_parser
OptionParser.new do |parser|
parser.banner = 'Usage: auto_hck.rb merge [merge options]'
parser.separator ''
define_options(parser)
parser.on_tail('-h', '--help', 'Show this message') do
puts parser
exit
end
end
end

def define_options(parser)
parser.on('-p', '--platform <platform_name>', String,
'Platform for Studio VM (determines HLK version)',
&method(:platform=))

parser.on('--packages <pkg1,pkg2,...>', Array,
'Comma-separated list of HLKX package paths to merge (minimum 2)',
&method(:packages=))

parser.on('--output <output_path>', String,
'Output path for the merged HLKX package',
&method(:output_file=))
end
end

class CLI < T::Struct
extend AutoHCK::Models::JsonHelper
extend T::Sig

prop :test, CliTestOptions, factory: -> { CliTestOptions.new }
prop :common, CliCommonOptions, factory: -> { CliCommonOptions.new }
prop :install, CliInstallOptions, factory: -> { CliInstallOptions.new }
prop :merge, CliMergeOptions, factory: -> { CliMergeOptions.new }
prop :mode, T.nilable(String), default: nil

sig { returns(T::Hash[String, OptionParser]) }
def sub_parser
@sub_parser ||= {
'test' => test.create_parser,
'install' => install.create_parser,
'functest' => test.create_parser
'functest' => test.create_parser,
'merge' => merge.create_parser
}
end

Expand Down
3 changes: 2 additions & 1 deletion lib/engines/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ module Engine
hcktest: HCKTest,
hckinstall: HCKInstall,
config_manager: ConfigManager,
functest: FunctestEngine
functest: FunctestEngine,
hlkxmerge: HLKXMerge
}.freeze

def self.select(name)
Expand Down
8 changes: 7 additions & 1 deletion lib/engines/hcktest/tools.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def connect(conn)

def config_clients_addrs
clients_addrs = {}
@clients.each_value do |client|
@clients&.each_value do |client|
clients_addrs[client.name] = {
addr: client.winrm_addr,
port: client.winrm_port
Expand Down Expand Up @@ -400,6 +400,12 @@ def create_project_package(project, playlist = nil, handler = nil, driver_path =
end
end

def merge_hlkx_packages(packages, output = nil)
retry_tools_command(__method__) do
act_with_tools { _1.merge_hlkx_packages(packages, output) }
end
end

def connection_check
retry_tools_command(__method__) do
act_with_tools(&:connection_check)
Expand Down
135 changes: 135 additions & 0 deletions lib/engines/hlkxmerge/hlkxmerge.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# typed: true
# frozen_string_literal: true

module AutoHCK
# HLKXMerge engine: merges multiple HLKX packages into one using the HLK API
# running on a Studio VM. No HLK clients or test execution are needed.
#
# Usage:
# auto_hck merge --platform <platform> --packages a.hlkx,b.hlkx --output merged.hlkx
class HLKXMerge
extend T::Sig
include Helper

ENGINE_MODE = 'merge'
PLATFORMS_JSON_DIR = 'lib/engines/hcktest/platforms'

def initialize(project)
@project = project
@logger = project.logger
@project.append_multilog('hlkxmerge.log')
end

def self.tag(options)
"merge-#{options.merge.platform}"
end

sig { params(logger: MultiLogger, options: CLI).returns(Models::HLKPlatform) }
def self.platform(logger, options)
platform_name = options.merge.platform
raise AutoHCKError, 'Missing required option: --platform' if platform_name.nil?
Comment thread
elizashurov marked this conversation as resolved.

Models::HLKPlatform.from_json_file(
"#{PLATFORMS_JSON_DIR}/#{platform_name}.json",
logger
)
end

def result_uploader_needed?
false
end

def drivers
[]
end

def test_steps
[]
end

sig { returns(T::Hash[String, T.untyped]) }
def clients_system_info
{}
end

def run
validate_options

ResourceScope.open do |scope|
boot_and_connect_studio(scope)
run_merge
end
end

private

def validate_options
packages = @project.options.merge.packages

raise AutoHCKError, 'At least 2 packages are required for merge' if packages.size < 2

packages.each do |pkg|
raise InvalidPathError, "Package file not found: #{pkg}" unless File.exist?(pkg)
end
end

def boot_and_connect_studio(scope)
@studio = @project.setup_manager.run_hck_studio(scope, {})
@logger.info('Waiting for Studio to load...')
sleep 5 until @studio.up?
@studio.connect
@studio.verify_tools
@logger.info('Studio connected')
end

def upload_packages
@project.options.merge.packages.map.with_index do |local_path, i|
filename = File.basename(local_path)
remote_path = "C:\\AutoHCK\\merge_input_#{i}_#{filename}"
@logger.info("Uploading #{filename} to Studio...")
@studio.tools.upload_to_studio(local_path, remote_path)
remote_path
end
end

def print_merge_results(result)
messages = (result['messages'] || []).map { " -- #{_1}\n" }.join
if result['iserror'] == false
@logger.info('Merge completed successfully')
@logger.debug("Merge result:\n#{messages}")
else
@logger.warn('Merge got an error. Check the logs for details.')
@logger.warn("Merge result:\n#{messages}")
end
end

def run_merge
remote_packages = upload_packages

@logger.info("Merging #{remote_packages.size} packages...")
result = @studio.tools.merge_hlkx_packages(remote_packages)
raise AutoHCKError, 'Merge failed: invalid response from Studio tools' unless result.is_a?(Hash)

print_merge_results(result)
raise AutoHCKError, 'Merge failed: Studio tools reported an error' unless result['iserror'] == false

downloaded_path = result['hostprojectpackagepath']
raise AutoHCKError, 'Merge failed: merged package path not found' unless downloaded_path

save_output(downloaded_path)
end

def save_output(downloaded_path)
output_file = @project.options.merge.output_file
if output_file && downloaded_path != output_file
FileUtils.mkdir_p(File.dirname(output_file))
FileUtils.mv(downloaded_path, output_file)
@logger.info("Merge complete. Output: #{output_file}")
else
@logger.info("Merge complete. Output: #{downloaded_path}")
end
rescue SystemCallError => e
raise AutoHCKError, "Failed to save merged package to #{output_file}: #{e.message}"
end
Comment thread
elizashurov marked this conversation as resolved.
end
end
Loading