docbrown/scripts/release
Jamie Gaskins f0edbcef90
Add support for versioned releases (#13750)
* Add release scripts

* Use `delete` over `gsub` with an empty string

Co-authored-by: Michael Kohl <citizen428@dev.to>

* wip

* wip

* Include stable release-channel branches in builds

* Add changelog stub

* Include the union of changes to the changelog

* Add things

* Add stuff

* Remove test changelog content

* Fix String#delete call

Extraneous `.` made Ruby parse it as a range

* Fix suggested release command

* Use backticks to denote a command to run

* Add debugging output to script

* Build more appropriate containers for stable

This includes tags

* Check if branch *starts with* release channel name

* Cache tag builds from production tag

* Skip trying to build containers for untagged pushes

* Clear out stubbed changelog

* Update PR template to incorporate CHANGELOG.md

* Run Rubocop on release scripts

This excludes some linter rules that only make sense in code that is
running as part of the Rails app. For example, we can't rely on
`ActiveSupport::TimeWithZone` because these scripts don't load Rails,
and we define top-level methods because they're scripts rather than
complex applications.

Co-authored-by: Michael Kohl <citizen428@dev.to>
2021-07-28 10:10:33 -04:00

93 lines
2.8 KiB
Ruby
Executable file

#!/usr/bin/env ruby
require "date"
require "optparse"
def run(command, abort_on_fail: true)
puts "> #{command}" if $VERBOSE
system(command, exception: abort_on_fail)
rescue StandardError => e
raise "#{command.inspect} failed: #{e}"
end
channel = ENV.fetch("FOREM_RELEASE_CHANNEL", "stable")
date = ENV.fetch("FOREM_RELEASE_DATE", Date.today.to_s).delete("-")
hotfix = ENV.fetch("FOREM_RELEASE_HOTFIX", 0)
remote = ENV.fetch("FOREM_RELEASE_REMOTE", "origin")
source = ENV.fetch("FOREM_STAGING_FROM", "#{channel}-next")
OptionParser.new ARGV.dup do |options|
options.banner = <<~USAGE
Usage: #{$PROGRAM_NAME} [options]
Releases are named CHANNEL.DATE.HOTFIX_COUNT. Example: #{channel}.#{date}.#{hotfix}
USAGE
options.on "-c", "--channel CHANNEL",
"Specify the release channel (defaults to #{channel.inspect})" do |release_channel|
channel = release_channel
end
options.on "-d", "--date DATE", "Specify the release date (defaults to today)" do |release_date|
date = release_date.delete("-")
end
options.on "-f", "--from BRANCH/COMMIT/TAG",
"Specify the source branch for this release (defaults to #{source.inspect})" do |from_branch|
source = from_branch
end
options.on "-h", "--hotfix HOTFIX",
"Specify the hotfix count for this release branch (defaults to #{hotfix.inspect})" do |hotfix_opt|
hotfix = hotfix_opt
end
options.on "-r", "--remote REMOTE", "Git remote to push to (defaults to #{remote.inspect})" do |git_remote|
remote = git_remote
end
options.on "-v", "--verbose", "Enable verbose mode" do
$VERBOSE = true
end
end.parse!
original_branch = `git branch --show-current`.strip
begin
tag = "#{channel}.#{date}.#{hotfix}"
puts "Building #{tag}..."
[source, channel].each do |branch|
run "git checkout --quiet #{branch}"
run "git pull --quiet --ff-only #{remote} #{branch}"
puts "Pulled latest #{branch.inspect}"
end
run "git merge --quiet #{source} --no-ff --message 'Merge #{source} into #{channel}'"
puts "Merged #{source} into #{channel}"
begin
run "git tag #{tag}"
puts "Tagged #{tag}"
rescue StandardError
# If `git tag` fails, it's because the tag already exists. In this case, git
# will have already output an error that looks like this:
#
# fatal: tag 'stable.20210512.0' already exists
#
warn "Should the hotfix count be set to something other than #{hotfix}?" \
"Or maybe you need to delete the tag locally (hint: `git tag --delete #{tag}`)"
exit 1
end
run "git push --quiet #{remote} #{channel}"
puts "Pushed #{channel} to #{remote}"
run "git push --quiet #{remote} #{tag}"
puts "Pushed #{tag} to #{remote}"
ensure
# Go back to the branch we were on before running this script
run "git checkout --quiet #{original_branch}"
end