Class: Discharger::Task
- Inherits:
-
Rake::TaskLib
- Object
- Rake::TaskLib
- Discharger::Task
- Defined in:
- lib/discharger/task.rb
Instance Attribute Summary collapse
-
#app_name ⇒ Object
Returns the value of attribute app_name.
-
#changelog_file ⇒ Object
Returns the value of attribute changelog_file.
-
#chat_token ⇒ Object
Returns the value of attribute chat_token.
-
#commit ⇒ Object
Returns the value of attribute commit.
-
#commit_finalize ⇒ Object
Returns the value of attribute commit_finalize.
-
#commit_identifier ⇒ Object
Returns the value of attribute commit_identifier.
-
#description ⇒ Object
Returns the value of attribute description.
-
#name ⇒ Object
Returns the value of attribute name.
-
#production_branch ⇒ Object
Returns the value of attribute production_branch.
-
#pull_request_url ⇒ Object
Returns the value of attribute pull_request_url.
-
#release_message_channel ⇒ Object
Returns the value of attribute release_message_channel.
-
#staging_branch ⇒ Object
Returns the value of attribute staging_branch.
-
#updated_paths ⇒ Object
Returns the value of attribute updated_paths.
-
#version_constant ⇒ Object
Returns the value of attribute version_constant.
-
#version_file ⇒ Object
Reissue settings.
-
#version_limit ⇒ Object
Returns the value of attribute version_limit.
-
#version_redo_proc ⇒ Object
Returns the value of attribute version_redo_proc.
-
#working_branch ⇒ Object
Returns the value of attribute working_branch.
Class Method Summary collapse
Instance Method Summary collapse
- #define ⇒ Object
-
#initialize(name = :release, tasker: Rake::Task) ⇒ Task
constructor
A new instance of Task.
-
#syscall(*steps, output: $stdout, error: $stderr) ⇒ Boolean
Run a multiple system commands and return true if all commands succeed If any command fails, the method will return false and stop executing any further commands.
-
#sysecho(message, output: $stdout) ⇒ Object
Echo a message to the console.
Constructor Details
#initialize(name = :release, tasker: Rake::Task) ⇒ Task
Returns a new instance of Task.
49 50 51 52 53 54 55 56 |
# File 'lib/discharger/task.rb', line 49 def initialize(name = :release, tasker: Rake::Task) @name = name @tasker = tasker @working_branch = "develop" @staging_branch = "stage" @production_branch = "main" @description = "Release the current version to #{staging_branch}" end |
Instance Attribute Details
#app_name ⇒ Object
Returns the value of attribute app_name.
36 37 38 |
# File 'lib/discharger/task.rb', line 36 def app_name @app_name end |
#changelog_file ⇒ Object
Returns the value of attribute changelog_file.
44 45 46 |
# File 'lib/discharger/task.rb', line 44 def changelog_file @changelog_file end |
#chat_token ⇒ Object
Returns the value of attribute chat_token.
35 36 37 |
# File 'lib/discharger/task.rb', line 35 def chat_token @chat_token end |
#commit ⇒ Object
Returns the value of attribute commit.
46 47 48 |
# File 'lib/discharger/task.rb', line 46 def commit @commit end |
#commit_finalize ⇒ Object
Returns the value of attribute commit_finalize.
47 48 49 |
# File 'lib/discharger/task.rb', line 47 def commit_finalize @commit_finalize end |
#commit_identifier ⇒ Object
Returns the value of attribute commit_identifier.
37 38 39 |
# File 'lib/discharger/task.rb', line 37 def commit_identifier @commit_identifier end |
#description ⇒ Object
Returns the value of attribute description.
26 27 28 |
# File 'lib/discharger/task.rb', line 26 def description @description end |
#name ⇒ Object
Returns the value of attribute name.
24 25 26 |
# File 'lib/discharger/task.rb', line 24 def name @name end |
#production_branch ⇒ Object
Returns the value of attribute production_branch.
30 31 32 |
# File 'lib/discharger/task.rb', line 30 def production_branch @production_branch end |
#pull_request_url ⇒ Object
Returns the value of attribute pull_request_url.
38 39 40 |
# File 'lib/discharger/task.rb', line 38 def pull_request_url @pull_request_url end |
#release_message_channel ⇒ Object
Returns the value of attribute release_message_channel.
32 33 34 |
# File 'lib/discharger/task.rb', line 32 def @release_message_channel end |
#staging_branch ⇒ Object
Returns the value of attribute staging_branch.
29 30 31 |
# File 'lib/discharger/task.rb', line 29 def staging_branch @staging_branch end |
#updated_paths ⇒ Object
Returns the value of attribute updated_paths.
45 46 47 |
# File 'lib/discharger/task.rb', line 45 def updated_paths @updated_paths end |
#version_constant ⇒ Object
Returns the value of attribute version_constant.
33 34 35 |
# File 'lib/discharger/task.rb', line 33 def version_constant @version_constant end |
#version_file ⇒ Object
Reissue settings
41 42 43 |
# File 'lib/discharger/task.rb', line 41 def version_file @version_file end |
#version_limit ⇒ Object
Returns the value of attribute version_limit.
42 43 44 |
# File 'lib/discharger/task.rb', line 42 def version_limit @version_limit end |
#version_redo_proc ⇒ Object
Returns the value of attribute version_redo_proc.
43 44 45 |
# File 'lib/discharger/task.rb', line 43 def version_redo_proc @version_redo_proc end |
#working_branch ⇒ Object
Returns the value of attribute working_branch.
28 29 30 |
# File 'lib/discharger/task.rb', line 28 def working_branch @working_branch end |
Class Method Details
.create(name = :release, tasker: Rake::Task, &block) ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/discharger/task.rb', line 8 def self.create(name = :release, tasker: Rake::Task, &block) task = new(name, tasker:) task.instance_eval(&block) if block Reissue::Task.create do |reissue| reissue.version_file = task.version_file reissue.version_limit = task.version_limit reissue.version_redo_proc = task.version_redo_proc reissue.changelog_file = task.changelog_file reissue.updated_paths = task.updated_paths reissue.commit = task.commit reissue.commit_finalize = task.commit_finalize end task.define task end |
Instance Method Details
#define ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/discharger/task.rb', line 111 def define require "slack-ruby-client" Slack.configure do |config| config.token = chat_token end 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 rebase #{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.", , ":chipmunk:") syscall ["git checkout #{working_branch}"] 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. Opening PR: #{pr_url} MSG end.then do |success| syscall ["open #{pr_url}"] if success 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 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}.", ) syscall ["git checkout #{working_branch}"] end end desc "Send a message to Slack." task :slack, [:text, :channel, :emoji] => :environment do |_, args| args.with_defaults( channel: , emoji: nil ) client = Slack::Web::Client.new = args.to_h [:icon_emoji] = .delete(:emoji) if [:emoji] sysecho "Sending message to Slack:".bg(:green).black + " #{args[:text]}" result = client.chat_postMessage(**) sysecho %(Message sent: #{result["ts"]}) end 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}"] ) 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}" 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. #{pr_url} Once the PR is merged, pull down #{working_branch} and run 'rake #{name}:stage' to stage the release branch. MSG end if continue syscall ["git checkout #{working_branch}"], ["open", pr_url] end end desc <<~DESC ---------- STEP 2 ---------- Stage the release branch This task will update Stage, open a PR, and instruct you on the next steps. NOTE: If you just want to update the stage environment but aren't ready to release, run: bin/rails #{name}:build DESC task stage: [:environment] do tasker["build"].invoke current_version = Object.const_get(version_constant) params = { expand: 1, title: "Release #{current_version} to production", body: <<~BODY Deploy #{current_version} to production. BODY } pr_url = "#{pull_request_url}/compare/#{production_branch}...#{staging_branch}?#{params.to_query}" sysecho <<~MSG Branch #{staging_branch} updated. Open a PR to #{production_branch} to release the version. Opening PR: #{pr_url} Once the PR is **approved**, run 'rake release' to release the version. MSG syscall ["open #{pr_url}"] end end end |
#syscall(*steps, output: $stdout, error: $stderr) ⇒ Boolean
Run a multiple system commands and return true if all commands succeed If any command fails, the method will return false and stop executing any further commands.
Provide a block to evaluate the output of the command and return true if the command was successful. If the block returns false, the method will return false and stop executing any further commands.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/discharger/task.rb', line 76 def syscall(*steps, output: $stdout, error: $stderr) success = false stdout, stderr, status = nil steps.each do |cmd| puts cmd.join(" ").bg(:green).black stdout, stderr, status = Open3.capture3(*cmd) if status.success? output.puts stdout success = true else error.puts stderr success = false exit(status.exitstatus) end end if block_given? success = !!yield(stdout, stderr, status) # If the error reports that a rule was bypassed, consider the command successful # because we are bypassing the rule intentionally when merging the release branch # to the production branch. success = true if stderr.match?(/bypassed rule violations/i) abort(stderr) unless success end success end |
#sysecho(message, output: $stdout) ⇒ Object
Echo a message to the console
return [TrueClass]
106 107 108 109 |
# File 'lib/discharger/task.rb', line 106 def sysecho(, output: $stdout) output.puts true end |