Skip to content

Commit 954bea7

Browse files
authored
Add revert-github-release script (#47)
1 parent 564267a commit 954bea7

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

exe/revert-github-release

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
# This script is used to revert a release that was created with the create-github-release gem
5+
# It will delete the release branch and tag locally and remotely
6+
7+
require 'create_github_release'
8+
9+
require 'English'
10+
require 'optparse'
11+
12+
# Options for running this script
13+
class Options
14+
attr_writer :default_branch, :release_version, :release_tag, :release_branch, :current_branch, :remote
15+
16+
def default_branch = @default_branch ||= 'main'
17+
def release_version = @release_version ||= `semverify current`.chomp
18+
def release_tag = @release_tag ||= "v#{release_version}"
19+
def release_branch = @release_branch ||= "release-#{release_tag}"
20+
def current_branch = @current_branch ||= `git rev-parse --abbrev-ref HEAD`.chomp
21+
def remote = @remote ||= 'origin'
22+
end
23+
24+
# Parse the command line options for this script
25+
class Parser
26+
# Create a new command line parser
27+
#
28+
# @example
29+
# parser = CommandLineParser.new
30+
#
31+
def initialize
32+
@option_parser = OptionParser.new
33+
define_options
34+
@options = Options.new
35+
end
36+
37+
attr_reader :option_parser, :options
38+
39+
# Parse the command line arguements returning the options
40+
#
41+
# @example
42+
# options = Parser.new.parse(*ARGV)
43+
#
44+
# @param args [Array<String>] the command line arguments
45+
#
46+
# @return [Options] the options
47+
#
48+
def parse(*args)
49+
begin
50+
option_parser.parse!(remaining_args = args.dup)
51+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
52+
report_errors(e.message)
53+
end
54+
parse_remaining_args(remaining_args)
55+
options
56+
end
57+
58+
private
59+
60+
# Output an error message and useage to stderr and exit
61+
# @return [void]
62+
# @api private
63+
def report_errors(*errors)
64+
warn error_message(errors)
65+
exit 1
66+
end
67+
68+
# The command line template as a string
69+
# @return [String]
70+
# @api private
71+
def command_template
72+
<<~COMMAND
73+
#{File.basename($PROGRAM_NAME)} [--help]
74+
COMMAND
75+
end
76+
77+
DESCRIPTION = <<~DESCRIPTION
78+
This script reverts the effect of running the create-github-release script.
79+
It must be run in the root directory of the work tree with the release
80+
branch checked out (which is the state create-github-release leaves you in).
81+
82+
This script should be run beefore the release PR is merged.
83+
84+
This script removes the release branch and release tag both in the local
85+
repository and on the remote. Deleting the branch on GitHub will close the
86+
GitHub PR automatically.
87+
DESCRIPTION
88+
89+
# Define the options for OptionParser
90+
# @return [void]
91+
# @api private
92+
def define_options
93+
option_parser.banner = "Usage: #{command_template}"
94+
option_parser.separator ''
95+
option_parser.separator DESCRIPTION
96+
option_parser.separator ''
97+
option_parser.separator 'Options:'
98+
99+
%i[
100+
define_help_option
101+
].each { |m| send(m) }
102+
end
103+
104+
# Define the help option
105+
# @return [void]
106+
# @api private
107+
def define_help_option
108+
option_parser.on_tail('-h', '--help', 'Show this message') do
109+
puts option_parser
110+
exit 0
111+
end
112+
end
113+
114+
# Parse non-option arguments
115+
# @return [void]
116+
# @api private
117+
def parse_remaining_args(remaining_args)
118+
# There should be no remaining args
119+
report_errors('Too many args') unless remaining_args.empty?
120+
end
121+
end
122+
123+
def in_work_tree? = `git rev-parse --is-inside-work-tree 2>/dev/null`.chomp == 'true'
124+
def in_root_directory? = `git rev-parse --show-toplevel 2>/dev/null`.chomp == Dir.pwd
125+
126+
def ref_exists?(name)
127+
`git rev-parse --verify #{name} >/dev/null 2>&1`
128+
$CHILD_STATUS.success?
129+
end
130+
131+
unless in_work_tree? && in_root_directory?
132+
warn 'ERROR: Not in the root directory of a Git work tree'
133+
exit 1
134+
end
135+
136+
# Parse the command line options
137+
options = Parser.new.parse(*ARGV)
138+
139+
unless options.release_branch == options.current_branch
140+
warn "ERROR: The current branch '#{options.current_branch}' is not the release branch for #{options.release_version}"
141+
exit 1
142+
end
143+
144+
unless ref_exists?(options.default_branch)
145+
warn "ERROR: The default branch '#{options.default_branch}' does not exist"
146+
exit 1
147+
end
148+
149+
`git checkout #{options.default_branch} >/dev/null`
150+
`git branch -D #{options.release_branch} >/dev/null`
151+
`git tag -d #{options.release_tag} >/dev/null`
152+
`git push #{options.remote} --delete #{options.release_branch} >/dev/null`
153+
`git push #{options.remote} --delete #{options.release_tag} >/dev/null`
154+
155+
puts "Reverted release #{options.release_version}"

0 commit comments

Comments
 (0)