Skip to content

Instantly share code, notes, and snippets.

@flyerhzm
Last active August 14, 2024 11:07
Show Gist options
  • Save flyerhzm/a82a63ac8ad761af2b60b248c6c39c49 to your computer and use it in GitHub Desktop.
Save flyerhzm/a82a63ac8ad761af2b60b248c6c39c49 to your computer and use it in GitHub Desktop.
Fetch gem changelogs based on Gemfile.lock diff, you can update gems in Gemfile.lock, then run `bundle exec ruby fetch_gem_changelogs.rb | more`
require 'bundler'
require 'net/http'
require 'json'
require 'uri'
# Function to fetch gem information from RubyGems.org
def fetch_gem_info(gem_name)
url = URI("https://rubygems.org/api/v1/gems/#{gem_name}.json")
response = Net::HTTP.get_response(url)
if response.is_a?(Net::HTTPSuccess)
JSON.parse(response.body)
else
nil
end
end
# Function to extract updated gems from `git diff`
def updated_gems
diff_output = `git diff Gemfile.lock`
gems = {}
diff_output.each_line do |line|
if line.match(/^\-\s+(\S+)\s+\((\d+\.\d+\.\d+)\)/)
gem_name, old_version = line.match(/^\-\s+(\S+)\s+\((\d+\.\d+\.\d+)\)/).captures
gems[gem_name] ||= {}
gems[gem_name][:old] = old_version
elsif line.match(/^\+\s+(\S+)\s+\((\d+\.\d+\.\d+)\)/)
gem_name, new_version = line.match(/^\+\s+(\S+)\s+\((\d+\.\d+\.\d+)\)/).captures
gems[gem_name] ||= {}
gems[gem_name][:new] = new_version
end
end
gems.select { |_, versions| versions[:old] && versions[:new] }
end
# Function to fetch and display relevant CHANGELOG sections
def fetch_and_display_changelog(gem_name, old_version, new_version, changelog_url, source_code_url)
# Check if the changelog_url is not on GitHub
unless changelog_url.include?('github.com')
# If source_code_url is on GitHub, construct the GitHub CHANGELOG URL
if source_code_url && source_code_url.include?('github.com')
changelog_url = "#{source_code_url}/blob/main/CHANGELOG.md"
else
puts "#{gem_name}: The changelog is not available on GitHub and no fallback could be constructed."
return
end
end
# Convert GitHub URL to raw URL if needed
if changelog_url.include?('github.com') && !changelog_url.include?('/raw/')
changelog_url = changelog_url.gsub('github.com', 'raw.githubusercontent.com').gsub('/blob/', '/')
end
uri = URI(changelog_url)
response = Net::HTTP.get_response(uri)
if response.is_a?(Net::HTTPSuccess)
changelog_content = response.body
extract_relevant_changelog(gem_name, old_version, new_version, changelog_content)
else
puts "#{gem_name}: Failed to fetch CHANGELOG from #{changelog_url}"
end
end
# Function to extract relevant section from the CHANGELOG content
def extract_relevant_changelog(gem_name, old_version, new_version, changelog_content)
puts "\n====================================================\n"
puts "#{gem_name} - Changes from version #{old_version} to #{new_version}:\n\n"
# Refined regex to match version headers more accurately
version_section_regex = /^##?.*\s*v?(\d+\.\d+\.\d+)/i
lines = changelog_content.lines
relevant_lines = []
capturing = false
lines.each do |line|
if line.match(version_section_regex)
version = line.match(version_section_regex)[1]
if Gem::Version.new(version) <= Gem::Version.new(new_version) && Gem::Version.new(version) > Gem::Version.new(old_version)
capturing = true
elsif Gem::Version.new(version) <= Gem::Version.new(old_version)
capturing = false
end
end
relevant_lines << line if capturing
end
if relevant_lines.empty?
puts "No specific changelog entries found between versions #{old_version} and #{new_version}."
else
puts relevant_lines.join
end
end
# Fetch updated gems list
gems_to_check = updated_gems
if gems_to_check.empty?
puts "No updated gems found in git diff."
else
gems_to_check.each do |gem_name, versions|
gem_info = fetch_gem_info(gem_name)
if gem_info
changelog_url = gem_info['changelog_uri']
source_code_url = gem_info['source_code_uri']
if changelog_url
fetch_and_display_changelog(gem_name, versions[:old], versions[:new], changelog_url, source_code_url)
elsif source_code_url && source_code_url.include?('github.com')
fetch_and_display_changelog(gem_name, versions[:old], versions[:new], "#{source_code_url}/blob/main/CHANGELOG.md", source_code_url)
else
puts "#{gem_name}: No changelog or source code URL found on RubyGems.org"
end
else
puts "#{gem_name}: Failed to fetch gem information from RubyGems.org"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment