Skip to content

Instantly share code, notes, and snippets.

@Thomascountz
Created February 28, 2025 13:19
Show Gist options
  • Save Thomascountz/cf4b956dc295414bf6451369594c2755 to your computer and use it in GitHub Desktop.
Save Thomascountz/cf4b956dc295414bf6451369594c2755 to your computer and use it in GitHub Desktop.
require "json"
require "open-uri"
require "date"
## DESCRIPTION:
# This script reads the Gemfile.lock of a Rails project and extracts the Rails
# version from each commit that updated the activerecord gem. It then uses the
# endoflife.date API to get the EOL date for each Rails version, and computes
# the number of days until EOL for each commit. Finally, it groups the results
# by year and prints the max, min, and avg "days until EOL" for each year.
## USAGE:
# ruby eol_hist.rb [repo_path]
# Pass repo path as first argument; default to current directory.
repo_path = ARGV[0] || "."
# 1. Get Rails EOL dates via endoflife.date API.
api_url = "https://endoflife.date/api/rails.json"
eol_entries = JSON.parse(URI.open(api_url).read)
eol_map = {}
eol_entries.each do |entry|
eol_map[entry["cycle"]] = Date.parse(entry["eol"])
end
# 2. Use git to get commits that updated activerecord in Gemfile.lock.
# We use the -C option to run git in the specified repo.
log_cmd = "git -C #{repo_path} log -G '^ activerecord ' --pretty=format:'%H %ad' --date=short -- Gemfile.lock"
git_log = `#{log_cmd}`
commits = git_log.lines.map do |line|
sha, date_str = line.split(" ", 2)
{ sha: sha, date: Date.parse(date_str.strip) }
end
# 3. For each commit, extract the new rails version from the diff.
results = []
commits.each do |commit|
diff = `git -C #{repo_path} show #{commit[:sha]} -- Gemfile.lock`
new_line = diff.each_line.find { |l| l.start_with?("+") && l.include?("activerecord") }
next unless new_line
if new_line =~ /\+ *activerecord\s+\(([^)]+)\)/
version_str = $1.strip
segments = version_str.split(".")
cycle = segments[0,2].join(".")
if eol_map[cycle]
days_until_eol = (eol_map[cycle] - commit[:date]).to_i
results << { year: commit[:date].year, days_until_eol: days_until_eol }
end
end
end
# 4. Group the results by year, then compute and print the max and min "days until EOL" for each year.
puts "Yearly stats for days until Rails EOL"
puts "-----------------------------------------"
grouped = results.group_by { |r| r[:year] }
header = sprintf("%-6s %10s %10s %10s %10s", "Year", "Max", "Min", "Med", "Avg")
puts header
puts "-" * header.size
grouped.keys.sort.each do |year|
values = grouped[year].map { |r| r[:days_until_eol] }
med = values.sum / values.size
avg = values.sum.to_f / values.size
puts sprintf("%-6d %10d %10d %10d %10.2f", year, values.max, values.min, med, avg)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment