Last active
September 17, 2024 14:43
-
-
Save DimaSamodurov/0e29828342c233102c5b26a2bea057e9 to your computer and use it in GitHub Desktop.
List nested branches down to the master branch based on PR sequence (using GitHub command line)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Colors | |
RED = 31 | |
GREEN = 32 | |
YELLOW = 33 | |
BLUE = 34 | |
end | |
class String | |
def colorize(color_code) | |
"\e[#{color_code}m#{self}\e[0m" | |
end | |
def red | |
colorize(Colors::RED) | |
end | |
def green | |
colorize(Colors::GREEN) | |
end | |
def yellow | |
colorize(Colors::YELLOW) | |
end | |
def blue | |
colorize(Colors::BLUE) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require_relative 'colorize' | |
require 'json' | |
# Script simplifies applying changes to the sequence of PRs. | |
# Scenario: You implement a feature in a long running branch but split by smaller, easy to read PRs: prA, prB, prC etc. | |
# so that we have sequence of branches: master > branchA, branchB, branchC etc. | |
# sometime(e.g. for testing), you need to synchronize updates from lower branches through entire sequence to the top. | |
# One strategy would be to merge all these branches into combined branch, another strategy - to merge branches bottom up: | |
# master to branchA, branchA to branchB, branchB to branchC etc. | |
# Current scrips helps running commands of this strategy. | |
# | |
# To use run: | |
# | |
# list-prs.rb <top-branch> | |
# | |
# As a result, sequence of branches will be saved to tmp/branch-sequence.txt, you can review it | |
# | |
# Then run merging in interactive mode: | |
# | |
# merge-branches.rb tmp/branch-sequence.txt | |
# | |
# Enjoy. | |
def get_pr_nesting(branch, base) | |
nesting = [] | |
loop do | |
print '.' | |
output = `gh pr view --json baseRefName,headRefName,url,title,statusCheckRollup #{branch}`.strip | |
break if output.empty? | |
json = JSON.parse output | |
nesting << json | |
branch = json.fetch("baseRefName") | |
print("\n") && break if branch == base | |
end | |
nesting | |
end | |
def is_green?(pr) | |
pr.fetch('statusCheckRollup').select{|check| check['__typename'] == 'StatusContext'}. | |
all? { |check| check['state'] == 'SUCCESS' } | |
end | |
### | |
branch = ARGV[0] || `git rev-parse --abbrev-ref HEAD`.strip | |
prs = get_pr_nesting(branch, ENV['base'] || 'master') | |
prs.reverse.each_with_index do |pr, i| | |
color = is_green?(pr) ? Colors::GREEN : Colors::RED | |
puts "#{(i+1).to_s.ljust(4).colorize(color)} #{pr['url']} #{pr['headRefName']}" | |
end | |
prs = (prs.map{|pr| pr['headRefName']} + ['master']).reverse | |
File.write 'tmp/branch-sequence.txt', prs.join("\n") | |
puts 'The list of PRs saved to "tmp/branch-sequence.txt" file' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require_relative 'colorize' | |
require 'io/console' | |
# This script helps merging sequence of branches | |
# stored in file specified as first argument (default tmp/branch-sequence.txt) | |
Input = Struct.new(:input) do | |
def continue? | |
["\r"].include? input | |
end | |
def skip? | |
[' '].include? input | |
end | |
end | |
def prompt(title, | |
message = "Press #{'Enter'.blue} to continue, #{'Space'.blue} to skip, or #{'any input'.blue} to cancel.") | |
puts title if title | |
puts message if message | |
Input.new(STDIN.getch).tap do |input| | |
next if input.continue? | |
puts 'Skipped.' and next if input.skip? | |
puts 'Cancelled.' | |
exit | |
end | |
end | |
prs = File.readlines(ARGV[0] || 'tmp/branch-sequence.txt').map(&:chomp) | |
puts 'Merging nested branches in order from top to bottom:' | |
puts prs.join("\n") | |
puts | |
prs.each_cons(2) do |a, b| | |
puts '------------------------------------------' | |
puts "Updating #{b.green}" | |
puts `git switch #{b}` # that will display branch status | |
status = `git status`.chomp | |
if status.include? 'Your branch is behind' | |
input = prompt 'Going to pull' | |
puts `git pull` if input.continue? | |
end | |
input = prompt "Merging #{a.green} into #{b.green}" | |
next puts 'Skipped' if input.skip? | |
# unlike ``, `system` command runs in interactive mode, opening editor with merge message if any | |
system "git merge #{a}" if input.continue? | |
puts status = `git status`.chomp | |
if status.include? 'branch is ahead of' | |
input = prompt 'Do you want to push?' | |
next puts 'Skipped' if input.skip? | |
puts `git push` if input.continue? | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment