-
Notifications
You must be signed in to change notification settings - Fork 376
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
require 'pathname' | ||
require 'rubygems' | ||
require 'json' | ||
require 'bundler' | ||
|
||
lib = File.expand_path('lib', __dir__) | ||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) | ||
require 'datadog' | ||
|
||
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/') | ||
@directory = directory | ||
@contrib_dir = contrib_dir | ||
@min_gems = { 'ruby' => {}, 'jruby' => {} } | ||
@max_gems = { 'ruby' => {}, 'jruby' => {} } | ||
@integration_json_mapping = {} | ||
end | ||
|
||
def process | ||
parse_gemfiles | ||
process_integrations | ||
include_hardcoded_versions | ||
write_output | ||
end | ||
|
||
private | ||
|
||
|
||
def parse_gemfiles(directory = 'gemfiles/') | ||
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 | ||
|
||
end | ||
|
||
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 | ||
|
||
def update_gem_versions(runtime, gem_name, version) | ||
return unless version_valid?(version) | ||
|
||
gem_version = Gem::Version.new(version) | ||
|
||
# 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 | ||
end | ||
end | ||
|
||
# Helper: Validate the version format | ||
def version_valid?(version) | ||
return false if version.nil? || version.strip.empty? | ||
|
||
Gem::Version.new(version) | ||
true | ||
rescue ArgumentError | ||
false | ||
end | ||
|
||
|
||
def process_integrations | ||
integrations = Datadog::Tracing::Contrib::REGISTRY.map(&:name).map(&:to_s) | ||
integrations.each do |integration| | ||
next if EXCLUDED_INTEGRATIONS.include?(integration) | ||
|
||
integration_name = resolve_integration_name(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 | ||
|
||
def include_hardcoded_versions | ||
# `httpx` is maintained externally | ||
@integration_json_mapping['httpx'] = [ | ||
'0.11', # Min version Ruby | ||
'0.11', # Max version Ruby | ||
nil, # Min version JRuby | ||
nil # Max version JRuby | ||
] | ||
|
||
# `makara` is part of `activerecord` | ||
@integration_json_mapping['makara'] = [ | ||
'0.3.5', # Min version Ruby | ||
'0.3.5', # Max version Ruby | ||
nil, # Min version JRuby | ||
nil # Max version JRuby | ||
] | ||
end | ||
|
||
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_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 | ||
|
||
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 | ||
|
||
GemfileProcessor.new.process |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
require 'json' | ||
|
||
input_file = 'gem_output.json' | ||
output_file = 'integration_versions.md' | ||
|
||
data = JSON.parse(File.read(input_file)) | ||
|
||
comment = "# Integrations\n\n" | ||
header = "| Integration | Ruby Min | Ruby Max | JRuby Min | JRuby Max |\n" | ||
separator = "|-------------|----------|-----------|----------|----------|\n" | ||
rows = data.map do |integration_name, versions| | ||
ruby_min, ruby_max, jruby_min, jruby_max = versions.map { |v| v || "None" } | ||
"| #{integration_name} | #{ruby_min} | #{ruby_max} | #{jruby_min} | #{jruby_max} |" | ||
end | ||
|
||
File.open(output_file, 'w') do |file| | ||
file.puts comment | ||
file.puts header | ||
file.puts separator | ||
rows.each { |row| file.puts row } | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
name: "Generate Supported Versions" | ||
|
||
on: | ||
workflow_dispatch: | ||
|
||
|
||
concurrency: | ||
group: ${{ github.workflow }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-22.04 | ||
permissions: | ||
contents: read | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Set up Ruby | ||
uses: ruby/setup-ruby@v1 | ||
with: | ||
bundler-cache: true # runs bundle install | ||
ruby-version: "3.3" | ||
|
||
- name: Update latest | ||
run: bundle exec ruby .github/scripts/find_gem_version_bounds.rb | ||
|
||
- name: Generate versions table | ||
run: ruby .github/scripts/generate_table_versions.rb | ||
|
||
- run: git diff | ||
|
||
- name: Create Pull Request | ||
id: cpr | ||
uses: peter-evans/create-pull-request@v7 | ||
with: | ||
token: ${{ secrets.GHA_PAT }} | ||
branch: auto-generate/update-supported-versions | ||
title: '[🤖] Update Supported Versions' | ||
base: master | ||
labels: dev/internal, integrations | ||
commit-message: "Test creating supported versions" | ||
delete-branch: true | ||
body: | | ||
This is a PR to update the table for supported integration versions. | ||
Workflow run: [Generate Supported Versions](https://github.com/DataDog/dd-trace-rb/actions/workflows/generate-supported-versions.yml) | ||
This should be tied to tracer releases, or triggered manually. | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.