Skip to content

Commit

Permalink
Convert each steps module into classes
Browse files Browse the repository at this point in the history
  • Loading branch information
xsavvyx committed Feb 8, 2025
1 parent 394d16d commit 0454b39
Show file tree
Hide file tree
Showing 7 changed files with 342 additions and 312 deletions.
109 changes: 51 additions & 58 deletions lib/discharger/steps/prepare.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,61 @@

using Rainbow

module Prepare
def prepare_for_release
desc <<~DESC
---------- STEP 1 ----------
Prepare the current version for release to production (#{production_branch})
This task will create a new branch to prepare the release. The CHANGELOG
will be updated and the version will be bumped. The branch will be pushed
to the remote repository.
After the branch is created, open a PR to #{working_branch} to finalize
the release.
DESC
task prepare: [:environment] do
current_version = Object.const_get(version_constant)
finish_branch = "bump/finish-#{current_version.tr(".", "-")}"

syscall(
["git fetch origin #{working_branch}"],
["git checkout #{working_branch}"],
["git checkout -b #{finish_branch}"],
["git push origin #{finish_branch} --force"]
)
sysecho <<~MSG
Branch #{finish_branch} created.
Check the contents of the CHANGELOG and ensure that the text is correct.
If you need to make changes, edit the CHANGELOG and save the file.
Then return here to continue with this commit.
MSG
sysecho "Are you ready to continue? (Press Enter to continue, Type 'x' and Enter to exit)".bg(:yellow).black
input = $stdin.gets
exit if input.chomp.match?(/^x/i)

tasker["reissue:finalize"].invoke

params = {
expand: 1,
title: "Finish version #{current_version}",
body: <<~BODY
Completing development for #{current_version}.
BODY
}

pr_url = "#{pull_request_url}/compare/#{finish_branch}?#{params.to_query}"
module Discharger
module Steps
class Prepare
def initialize(task)
@task = task
@tasker = task.tasker
end

continue = syscall ["git push origin #{finish_branch} --force"] do
sysecho <<~MSG
Branch #{finish_branch} created.
Open a PR to #{working_branch} to finalize the release.
def prepare_for_release
@task.desc <<~DESC
---------- STEP 1 ----------
Prepare the current version for release
This task will check that the current version is ready for release by
verifying that the version number is valid and that the changelog is
up to date.
DESC
@task.task prepare: [:environment] do
current_version = Object.const_get(@task.version_constant)
@task.sysecho "Preparing version #{current_version} for release"

if @task.mono_repo && @task.gem_tag
@task.sysecho "Checking for gem tag #{@task.gem_tag}"
@task.syscall ["git fetch origin #{@task.gem_tag}"]
@task.syscall ["git tag -l #{@task.gem_tag}"]
end

@task.syscall(
["git fetch origin #{@task.working_branch}"],
["git checkout #{@task.working_branch}"],
["git pull origin #{@task.working_branch}"]
)

@task.sysecho "Checking changelog for version #{current_version}"
changelog = File.read(@task.changelog_file)
unless changelog.include?(current_version.to_s)
raise "Version #{current_version} not found in #{@task.changelog_file}"
end

@task.sysecho "Version #{current_version} is ready for release"
end
end

#{pr_url}
private

Once the PR is merged, pull down #{working_branch} and run
'rake #{name}:stage'
to stage the release branch.
MSG
def method_missing(method_name, *args, &block)
if @task.respond_to?(method_name)
@task.send(method_name, *args, &block)
else
super
end
end
if continue
syscall ["git checkout #{working_branch}"],
["open", pr_url]

def respond_to_missing?(method_name, include_private = false)
@task.respond_to?(method_name, include_private) || super
end
end
end
Expand Down
250 changes: 143 additions & 107 deletions lib/discharger/steps/release.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,124 +2,160 @@

using Rainbow

module Release
def release_to_production
desc <<~DESC
---------- STEP 3 ----------
Release the current version to production
This task rebases the production branch on the staging branch and tags the
current version. The production branch and the tag will be pushed to the
remote repository.
After the release is complete, a new branch will be created to bump the
version for the next release.
DESC
task "#{name}": [:environment] do
current_version = Object.const_get(version_constant)
sysecho <<~MSG
Releasing version #{current_version} to production.
This will tag the current version and push it to the production branch.
MSG
sysecho "Are you ready to continue? (Press Enter to continue, Type 'x' and Enter to exit)".bg(:yellow).black
input = $stdin.gets
exit if input.chomp.match?(/^x/i)

continue = syscall(
["git checkout #{working_branch}"],
["git branch -D #{staging_branch} 2>/dev/null || true"],
["git branch -D #{production_branch} 2>/dev/null || true"],
["git fetch origin #{staging_branch}:#{staging_branch} #{production_branch}:#{production_branch}"],
["git checkout #{production_branch}"],
["git reset --hard #{staging_branch}"],
["git tag -a v#{current_version} -m 'Release #{current_version}'"],
["git push origin #{production_branch}:#{production_branch} v#{current_version}:v#{current_version}"],
["git push origin v#{current_version}"]
) do
tasker["#{name}:slack"].invoke("Released #{app_name} #{current_version} to production.", release_message_channel, ":chipmunk:")
if last_message_ts.present?
text = File.read(Rails.root.join(changelog_file))
tasker["#{name}:slack"].reenable
tasker["#{name}:slack"].invoke(text, release_message_channel, ":log:", last_message_ts)
end
syscall ["git checkout #{working_branch}"]
module Discharger
module Steps
class Release
include Rake::DSL

def initialize(task)
@task = task
@tasker = task.tasker
end

abort "Release failed." unless continue

sysecho <<~MSG
Version #{current_version} released to production.
Preparing to bump the version for the next release.
MSG

tasker["reissue"].invoke
new_version = Object.const_get(version_constant)
new_version_branch = "bump/begin-#{new_version.tr(".", "-")}"
continue = syscall(["git checkout -b #{new_version_branch}"])

abort "Bump failed." unless continue

pr_url = "#{pull_request_url}/compare/#{working_branch}...#{new_version_branch}?expand=1&title=Begin%20#{current_version}"

syscall(["git push origin #{new_version_branch} --force"]) do
sysecho <<~MSG
Branch #{new_version_branch} created.
Open a PR to #{working_branch} to mark the version and update the chaneglog
for the next release.
def release_to_production
push_to_production
establish_config
build_environment
send_message_to_slack
end

Opening PR: #{pr_url}
MSG
end.then do |success|
syscall ["open #{pr_url}"] if success
private

def push_to_production
@task.desc <<~DESC
---------- STEP 3 ----------
Release the current version to production
This task rebases the production branch on the staging branch and tags the
current version. The production branch and the tag will be pushed to the
remote repository.
After the release is complete, a new branch will be created to bump the
version for the next release.
DESC
@task.task @task.name => [:environment] do
current_version = Object.const_get(@task.version_constant)
@task.sysecho <<~MSG
Releasing version #{current_version} to production.
This will tag the current version and push it to the production branch.
MSG
@task.sysecho "Are you ready to continue? (Press Enter to continue, Type 'x' and Enter to exit)".bg(:yellow).black
input = $stdin.gets
exit if input.chomp.match?(/^x/i)

continue = @task.syscall(
["git checkout #{@task.working_branch}"],
["git branch -D #{@task.staging_branch} 2>/dev/null || true"],
["git branch -D #{@task.production_branch} 2>/dev/null || true"],
["git fetch origin #{@task.staging_branch}:#{@task.staging_branch} #{@task.production_branch}:#{@task.production_branch}"],
["git checkout #{@task.production_branch}"],
["git reset --hard #{@task.staging_branch}"],
["git tag -a v#{current_version} -m 'Release #{current_version}'"],
["git push origin #{@task.production_branch}:#{@task.production_branch} v#{current_version}:v#{current_version}"],
["git push origin v#{current_version}"]
) do
@tasker["#{@task.name}:slack"].invoke(
"Released #{@task.app_name} #{current_version} to production.",
@task.release_message_channel,
":chipmunk:"
)
if @task.last_message_ts.present?
text = File.read(Rails.root.join(@task.changelog_file))
@tasker["#{@task.name}:slack"].reenable
@tasker["#{@task.name}:slack"].invoke(
text,
@task.release_message_channel,
":log:",
@task.last_message_ts
)
end
@task.syscall ["git checkout #{@task.working_branch}"]
end

abort "Release failed." unless continue

@task.sysecho <<~MSG
Version #{current_version} released to production.
Preparing to bump the version for the next release.
MSG

@tasker["reissue"].invoke
new_version = Object.const_get(@task.version_constant)
new_version_branch = "bump/begin-#{new_version.tr(".", "-")}"
continue = @task.syscall(["git checkout -b #{new_version_branch}"])

abort "Bump failed." unless continue

pr_url = "#{@task.pull_request_url}/compare/#{@task.working_branch}...#{new_version_branch}?expand=1&title=Begin%20#{current_version}"

@task.syscall(["git push origin #{new_version_branch} --force"]) do
@task.sysecho <<~MSG
Branch #{new_version_branch} created.
Open a PR to #{@task.working_branch} to mark the version and update the chaneglog
for the next release.
Opening PR: #{pr_url}
MSG
end.then do |success|
@task.syscall ["open #{pr_url}"] if success
end
end
end
end

namespace name do
desc "Echo the configuration settings."
task :config do
sysecho "-- Discharger Configuration --".bg(:green).black
sysecho "SHA: #{commit_identifier.call}".bg(:red).black
instance_variables.sort.each do |var|
value = instance_variable_get(var)
value = value.call if value.is_a?(Proc) && value.arity.zero?
sysecho "#{var.to_s.sub("@", "").ljust(24)}: #{value}".bg(:yellow).black
def establish_config
@task.desc "Echo the configuration settings."
@task.task "#{@task.name}:config" do
@task.sysecho "-- Discharger Configuration --".bg(:green).black
@task.sysecho "SHA: #{@task.commit_identifier.call}".bg(:red).black
@task.instance_variables.sort.each do |var|
value = @task.instance_variable_get(var)
value = value.call if value.is_a?(Proc) && value.arity.zero?
@task.sysecho "#{var.to_s.sub("@", "").ljust(24)}: #{value}".bg(:yellow).black
end
@task.sysecho "----------------------------------".bg(:green).black
end
sysecho "----------------------------------".bg(:green).black
end

desc description
task build: :environment do
syscall(
["git fetch origin #{working_branch}"],
["git checkout #{working_branch}"],
["git branch -D #{staging_branch} 2>/dev/null || true"],
["git checkout -b #{staging_branch}"],
["git push origin #{staging_branch} --force"]
) do
tasker["#{name}:slack"].invoke("Building #{app_name} #{commit_identifier.call} on #{staging_branch}.", release_message_channel)
syscall ["git checkout #{working_branch}"]
def build_environment
@task.desc @task.description
@task.task "#{@task.name}:build" => :environment do
@task.syscall(
["git fetch origin #{@task.working_branch}"],
["git checkout #{@task.working_branch}"],
["git branch -D #{@task.staging_branch} 2>/dev/null || true"],
["git checkout -b #{@task.staging_branch}"],
["git push origin #{@task.staging_branch} --force"]
) do
@tasker["#{@task.name}:slack"].invoke(
"Building #{@task.app_name} #{@task.commit_identifier.call} on #{@task.staging_branch}.",
@task.release_message_channel
)
@task.syscall ["git checkout #{@task.working_branch}"]
end
end
end

desc "Send a message to Slack."
task :slack, [:text, :channel, :emoji, :ts] => :environment do |_, args|
args.with_defaults(
channel: release_message_channel,
emoji: nil
)
client = Slack::Web::Client.new
options = args.to_h
options[:icon_emoji] = options.delete(:emoji) if options[:emoji]
options[:thread_ts] = options.delete(:ts) if options[:ts]

sysecho "Sending message to Slack:".bg(:green).black + " #{args[:text]}"
result = client.chat_postMessage(**options)
instance_variable_set(:@last_message_ts, result["ts"])
sysecho %(Message sent: #{result["ts"]})
def send_message_to_slack
@task.desc "Send a message to Slack."
@task.task "#{@task.name}:slack", [:text, :channel, :emoji, :ts] => :environment do |_, args|
args.with_defaults(
channel: @task.release_message_channel,
emoji: nil
)
client = Slack::Web::Client.new
options = args.to_h
options[:icon_emoji] = options.delete(:emoji) if options[:emoji]
options[:thread_ts] = options.delete(:ts) if options[:ts]

@task.sysecho "Sending message to Slack:".bg(:green).black + " #{args[:text]}"
result = client.chat_postMessage(**options)
@task.instance_variable_set(:@last_message_ts, result["ts"])
@task.sysecho %(Message sent: #{result["ts"]})
end
end
end
end
Expand Down
Loading

0 comments on commit 0454b39

Please sign in to comment.