diff --git a/.github/scripts/find_gem_version_bounds.rb b/.github/scripts/find_gem_version_bounds.rb index cdddfeec8a..48fe34278e 100644 --- a/.github/scripts/find_gem_version_bounds.rb +++ b/.github/scripts/find_gem_version_bounds.rb @@ -7,124 +7,129 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'datadog' -def parse_gemfiles(directory = 'gemfiles/') - min_gems = { 'ruby' => {}, 'jruby' => {} } - max_gems = { 'ruby' => {}, 'jruby' => {} } - - gemfiles = Dir.glob(File.join(directory, '*')) - gemfiles.each do |gemfile_name| - runtime = File.basename(gemfile_name).split('_').first # ruby or jruby - next unless %w[ruby jruby].include?(runtime) - # parse the gemfile - if gemfile_name.end_with?(".gemfile") - process_gemfile(gemfile_name, runtime, min_gems, max_gems) - elsif gemfile_name.end_with?('.gemfile.lock') - process_lockfile(gemfile_name, runtime, min_gems, max_gems) - end +class GemfileProcessor + SPECIAL_CASES = { + "opensearch" => "OpenSearch" # special case because opensearch = OpenSearch not Opensearch + }.freeze + EXCLUDED_INTEGRATIONS = ["configuration", "propagation", "utils"].freeze + + def initialize(directory: 'gemfiles/', contrib_dir: 'lib/datadog/tracing/contrib/') + # TODO: HERE + @directory = directory + @contrib_dir = contrib_dir + @min_gems = { 'ruby' => {}, 'jruby' => {} } + @max_gems = { 'ruby' => {}, 'jruby' => {} } + @integration_json_mapping = {} end - [min_gems['ruby'], min_gems['jruby'], max_gems['ruby'], max_gems['jruby']] -end - -def process_gemfile(gemfile_name, runtime, min_gems, max_gems) - begin - definition = Bundler::Definition.build(gemfile_name, nil, nil) - definition.dependencies.each do |dependency| - gem_name = dependency.name - version = dependency.requirement.to_s - update_gem_versions(runtime, gem_name, version, min_gems, max_gems) - end - rescue Bundler::GemfileError => e - puts "Error reading Gemfile: #{e.message}" + def process + # TODO: HERE + parse_gemfiles + process_integrations + write_output end -end -def process_lockfile(gemfile_name, runtime, min_gems, max_gems) - lockfile_contents = File.read(gemfile_name) - parser = Bundler::LockfileParser.new(lockfile_contents) - parser.specs.each do |spec| - gem_name = spec.name - version = spec.version.to_s - update_gem_versions(runtime, gem_name, version, min_gems, max_gems) - end -end + private + -def update_gem_versions(runtime, gem_name, version, min_gems, max_gems) - return unless version_valid?(version) + def parse_gemfiles(directory = 'gemfiles/') + # min_gems = { 'ruby' => {}, 'jruby' => {} } + # max_gems = { 'ruby' => {}, 'jruby' => {} } - gem_version = Gem::Version.new(version) + gemfiles = Dir.glob(File.join(@directory, '*')) + gemfiles.each do |gemfile_name| + runtime = File.basename(gemfile_name).split('_').first # ruby or jruby + next unless %w[ruby jruby].include?(runtime) + # parse the gemfile + if gemfile_name.end_with?(".gemfile") + process_gemfile(gemfile_name, runtime) + elsif gemfile_name.end_with?('.gemfile.lock') + process_lockfile(gemfile_name, runtime) + end + end - # Update minimum gems - if min_gems[runtime][gem_name].nil? || gem_version < Gem::Version.new(min_gems[runtime][gem_name]) - min_gems[runtime][gem_name] = version end - # Update maximum gems - if max_gems[runtime][gem_name].nil? || gem_version > Gem::Version.new(max_gems[runtime][gem_name]) - max_gems[runtime][gem_name] = version + def process_gemfile(gemfile_name, runtime) + begin + definition = Bundler::Definition.build(gemfile_name, nil, nil) + definition.dependencies.each do |dependency| + gem_name = dependency.name + version = dependency.requirement.to_s + update_gem_versions(runtime, gem_name, version) + end + rescue Bundler::GemfileError => e + puts "Error reading Gemfile: #{e.message}" + end + end + + def process_lockfile(gemfile_name, runtime) + lockfile_contents = File.read(gemfile_name) + parser = Bundler::LockfileParser.new(lockfile_contents) + parser.specs.each do |spec| + gem_name = spec.name + version = spec.version.to_s + update_gem_versions(runtime, gem_name, version) + end end -end + def update_gem_versions(runtime, gem_name, version) + return unless version_valid?(version) + gem_version = Gem::Version.new(version) -# Helper: Validate the version format -def version_valid?(version) - return false if version.nil? + # Update minimum gems + if @min_gems[runtime][gem_name].nil? || gem_version < Gem::Version.new(@min_gems[runtime][gem_name]) + @min_gems[runtime][gem_name] = version + end - version = version.to_s.strip + # Update maximum gems + if @max_gems[runtime][gem_name].nil? || gem_version > Gem::Version.new(@max_gems[runtime][gem_name]) + @max_gems[runtime][gem_name] = version + end + end - return false if version.empty? + # Helper: Validate the version format + def version_valid?(version) + return false if version.nil? || version.strip.empty? - # Ensure it's a valid Gem::Version - begin Gem::Version.new(version) true rescue ArgumentError false end -end -def get_integration_names(directory = 'lib/datadog/tracing/contrib/') - Datadog::Tracing::Contrib::REGISTRY.map{ |i| i.name.to_s } -end - -SPECIAL_CASES = { - "opensearch" => "OpenSearch" # special case because opensearch = OpenSearch not Opensearch -}.freeze -excluded = ["configuration", "propagation", "utils"] -min_gems_ruby, min_gems_jruby, max_gems_ruby, max_gems_jruby = parse_gemfiles("gemfiles/") -integrations = get_integration_names('lib/datadog/tracing/contrib/') + def process_integrations + integrations = Datadog::Tracing::Contrib::REGISTRY.map(&:name).map(&:to_s) + integrations.each do |integration| + next if EXCLUDED_INTEGRATIONS.include?(integration) -integration_json_mapping = {} + integration_name = resolve_integration_name(integration) -integrations.each do |integration| - next if excluded.include?(integration) + @integration_json_mapping[integration] = [ + @min_gems['ruby'][integration_name], + @max_gems['ruby'][integration_name], + @min_gems['jruby'][integration_name], + @max_gems['jruby'][integration_name] + ] + end + end - begin + def resolve_integration_name(integration) mod_name = SPECIAL_CASES[integration] || integration.split('_').map(&:capitalize).join module_name = "Datadog::Tracing::Contrib::#{mod_name}" integration_module = Object.const_get(module_name)::Integration - integration_name = integration_module.respond_to?(:gem_name) ? integration_module.gem_name : integration - rescue NameError - puts "Integration module not found for #{integration}, falling back to integration name." - integration_name = integration - rescue NoMethodError - puts "gem_name method missing for #{integration}, falling back to integration name." - integration_name = integration + integration_module.respond_to?(:gem_name) ? integration_module.gem_name : integration + rescue NameError, NoMethodError + puts "Fallback for #{integration}: module or gem_name not found." + integration end - min_version_jruby = min_gems_jruby[integration_name] - min_version_ruby = min_gems_ruby[integration_name] - max_version_jruby = max_gems_jruby[integration_name] - max_version_ruby = max_gems_ruby[integration_name] - - integration_json_mapping[integration] = [ - min_version_ruby, max_version_ruby, - min_version_jruby, max_version_jruby - ] + def write_output + @integration_json_mapping = @integration_json_mapping.sort.to_h + File.write("gem_output.json", JSON.pretty_generate(@integration_json_mapping)) + end end -# Sort and output the mapping -integration_json_mapping = integration_json_mapping.sort.to_h -File.write("gem_output.json", JSON.pretty_generate(integration_json_mapping)) \ No newline at end of file +GemfileProcessor.new.process \ No newline at end of file