#!/usr/bin/env ruby require "bundler/inline" gemfile do source "https://rubygems.org" gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__) end require "active_support/core_ext/object/blank" require "active_support/core_ext/string/inflections" DISPLAY_FORMATS = %w[commit pr-title pr-label] opts = Optimist.options do synopsis "Show the git commit log between two refs for all git repos." opt :from, "The commit log 'from' ref", :type => :string, :required => true opt :to, "The commit log 'to' ref" , :type => :string, :required => true opt :display, "How to display the history. Valid values are: #{DISPLAY_FORMATS.join(", ")}", :default => "commit" opt :summary, "Display a summary of the repos.", :default => false opt :skip, "The repos to skip", :type => :strings, :default => [] MultiRepo::CLI.common_options(self, :except => :dry_run) end Optimist.die :display, "must be one of: #{DISPLAY_FORMATS.join(", ")}" unless DISPLAY_FORMATS.include?(opts[:display]) range = "#{opts[:from]}..#{opts[:to]}" puts "Git commit log between #{opts[:from]} and #{opts[:to]}\n\n" repos_with_changes = [] MultiRepo::CLI.repos_for(**opts).each do |repo| next if opts[:skip].include?(repo.name) puts MultiRepo::CLI.header(repo.name) repo.git.fetch(output: false) case opts[:display] when "pr-label", "pr-title" github ||= MultiRepo::Service::Github.client pr_label_display = opts[:display] == "pr-label" results = {} if pr_label_display results["bug"] = [] results["enhancement"] = [] end results["other"] = [] log = begin repo.git.client.capturing.log({:oneline => true}, range) rescue MiniGit::GitError puts "ERROR: commit range not found.".light_red puts next end log.lines.each do |line| next unless (match = line.match(/Merge pull request #(\d+)\b/)) pr = begin github.pull_request(repo.name, match[1]) rescue Octokit::NotFound next # PR not found could mean this was a cherry-pick from a different repo, so the PR doesn't exist. end label = pr.labels.detect { |l| results.key?(l.name) }&.name || "other" results[label] << pr end changes_found = false results.each do |label, prs| next if prs.blank? changes_found = true puts "\n## #{label.titleize}\n\n" if pr_label_display prs.each do |pr| puts "* #{pr.title} [[##{pr.number}]](#{pr.html_url})" end end repos_with_changes << repo if changes_found when "commit" output = begin repo.git.client.capturing.log({:oneline => true, :decorate => true, :graph => true}, range) rescue MiniGit::GitError puts "ERROR: commit range not found.".light_red puts next end puts output repos_with_changes << repo if output.present? end puts end if opts[:summary] && repos_with_changes.any? puts puts "Here are the changes per affected repository in GitHub:" repos_with_changes.each do |repo| puts "* [#{repo.name}](https://github.com/#{repo.name}/compare/#{opts[:from]}...#{opts[:to]})" end puts end