Skip to content

Instantly share code, notes, and snippets.

@vitroz
Last active August 5, 2025 12:36
Show Gist options
  • Save vitroz/e03e14464e6555fcb91a84180f360260 to your computer and use it in GitHub Desktop.
Save vitroz/e03e14464e6555fcb91a84180f360260 to your computer and use it in GitHub Desktop.
libyears report
#!/usr/bin/env ruby
require "fileutils"
require "open3"
require "date"
class LibyearReportGenerator
REPOSITORIES = [
"/Users/vitorqueiroz/dev/smile-core",
"/Users/vitorqueiroz/dev/smile-data-ingestion-endpoints",
"/Users/vitorqueiroz/dev/smile-data-ingestion-pipeline",
"/Users/vitorqueiroz/dev/smile-ruby-monitoring"
].freeze
def initialize
@current_dir = Dir.pwd
end
def generate_reports
puts "Starting libyear-bundler report generation for #{REPOSITORIES.size} repositories..."
puts "=" * 60
# Use threads to process repos in parallel
threads = REPOSITORIES.map do |repo_path|
Thread.new { process_repository(repo_path) }
end
threads.each(&:join)
puts "\n" + "=" * 60
puts "All reports generated successfully!"
puts "Reports saved in: #{@current_dir}"
end
private
def process_repository(repo_path)
repo_name = File.basename(repo_path)
puts "\nProcessing #{repo_name}..."
unless Dir.exist?(repo_path)
puts " ❌ Repository not found: #{repo_path}"
return
end
begin
Dir.chdir(repo_path) do
# Git operations
puts " πŸ”„ Switching to main branch and pulling latest changes..."
run_command("git checkout main")
run_command("git pull")
# Run libyear-bundler commands
puts " πŸ“Š Running libyear-bundler analysis..."
# Special handling for smile-ruby-monitoring repo
if repo_name == "smile-ruby-monitoring"
libyear_output = run_command("libyear-bundler")
version_output = run_command("libyear-bundler --versions")
else
libyear_output = run_command("smile-cli run libyear-bundler")
version_output = run_command("smile-cli run libyear-bundler --versions")
end
# Generate report
generate_report_file(repo_name, libyear_output, version_output)
puts " βœ… Report generated for #{repo_name}"
end
rescue => e
puts " ❌ Error processing #{repo_name}: #{e.message}"
end
end
def run_command(command)
stdout, stderr, status = Open3.capture3(command)
unless status.success?
raise "Command failed: #{command}\nError: #{stderr}"
end
stdout
end
def generate_report_file(repo_name, libyear_output, version_output)
filename = "#{@current_dir}/#{repo_name}_libyear_bundler_report.txt"
# Parse the outputs for summary
summary = parse_libyear_summary(libyear_output, version_output)
File.open(filename, "w") do |file|
file.puts "LIBYEAR-BUNDLER REPORT FOR #{repo_name.upcase}"
file.puts "=" * 50
file.puts "Generated on: #{DateTime.now.strftime("%Y-%m-%d %H:%M:%S")}"
file.puts ""
# Summary section
file.puts "SUMMARY:"
file.puts "-" * 20
file.puts summary
file.puts ""
# Version information
file.puts "VERSION INFORMATION:"
file.puts "-" * 20
file.puts version_output.strip
file.puts ""
# Full libyear-bundler output
file.puts "FULL LIBYEAR-BUNDLER OUTPUT:"
file.puts "-" * 20
file.puts libyear_output
end
end
def parse_libyear_summary(libyear_output, version_output)
summary = []
# Extract critical version information first (most important)
versions_behind = parse_versions_behind(version_output)
summary << versions_behind if versions_behind
# Extract total libyears from output
if libyear_output =~ /Total: ([\d.]+) libyears?/
total_libyears = $1
summary << "Total Libyears: #{total_libyears}"
else
# Try to find libyears mentioned in the output
libyear_lines = libyear_output.scan(/[\d.]+\s+libyears?/)
summary << if libyear_lines.any?
"Libyears found in output: #{libyear_lines.join(", ")}"
else
"Total Libyears: Unable to parse from output"
end
end
# Add gem count if available
gem_count = count_outdated_gems(libyear_output)
summary << "Outdated gems analyzed: #{gem_count}" if gem_count > 0
summary.join("\n")
end
def parse_versions_behind(version_output)
# Look for the critical pattern: "Major, minor, patch versions behind: 3, 91, 13"
if version_output =~ /Major, minor, patch versions behind:\s*(\d+),\s*(\d+),\s*(\d+)/i
major, minor, patch = $1, $2, $3
"Major, minor, patch versions behind: #{major}, #{minor}, #{patch}"
elsif version_output =~ /(\d+)\s+major.*?(\d+)\s+minor.*?(\d+)\s+patch/im
major, minor, patch = $1, $2, $3
"Major, minor, patch versions behind: #{major}, #{minor}, #{patch}"
end
end
def count_outdated_gems(output)
# Count lines that look like gem entries (typically have version numbers)
gem_lines = output.lines.select do |line|
line.match?(/\d+\.\d+/) && !line.match?(/^(Total|Checked)/)
end
gem_lines.size
end
end
# Run the script
if __FILE__ == $0
begin
generator = LibyearReportGenerator.new
generator.generate_reports
rescue Interrupt
puts "\n\n⚠️ Script interrupted by user"
exit 1
rescue => e
puts "\n❌ Script failed: #{e.message}"
puts e.backtrace.first(5).join("\n") if ENV["DEBUG"]
exit 1
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment