heroku_tool 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 366d3213e1b652d45f89a3cdc8cd76ccfdf48c5727c13cbdcf215cef666c1a2e
4
- data.tar.gz: 315e1c68673b6f3af2d944633b19d3f75d3856a9e8d81d028ada208834cd9759
3
+ metadata.gz: 54667e338f64d0555965c42828d5e5363bded258cb60e55af76e5a2339bb9c03
4
+ data.tar.gz: c1d86d98c1ade53354d5e7f1d54d3bac19d6749e57bdd24cd17400d2172cd6d4
5
5
  SHA512:
6
- metadata.gz: ee39dd422b621fe18873394e5ae60e68f6294137de76dc0bfa67e084e4763791edc4d2bb74f1e7f0ccd2e4e05e0113b0ad9b38f92c0e825445d4095064cceb80
7
- data.tar.gz: b9b3254bb923175c97f69ead7cb9658063a94ed499bb41b0da30075e406cd1c0b31a41127e924593a0f9f27df542e81940529d0bb0514c385c22888cc6fa21cb
6
+ metadata.gz: bfcd540d5d6072385d293792819d519a5bf717a7eeca4bde76eac45975e9e967ef2fca9a85b38c173d7a5088f5e76d0e9e76c39dd6adff810f869ea6a60167e8
7
+ data.tar.gz: 15dde81dbe811594f2abdc88ed79b9d60c5b5e76b0c920b1ecf97de93c92d493a72776b0f3e2e9b3f456ec5f2d25eb5bc232edb4ec29b19ac845407d19853d21
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+
12
+ strategy:
13
+ matrix:
14
+ ruby-version: ['3.2', '3.3', '3.4', '4.0']
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - name: Set up Ruby
19
+ uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby-version }}
22
+ bundler-cache: true
23
+ - name: Run tests
24
+ run: bundle exec rake
25
+ - name: Run rubocop
26
+ run: bundle exec rubocop
data/.rubocop.yml ADDED
@@ -0,0 +1,49 @@
1
+ require:
2
+ - standard
3
+ plugins:
4
+ - rubocop-rspec
5
+
6
+ inherit_gem:
7
+ standard: config/base.yml
8
+
9
+ AllCops:
10
+ TargetRubyVersion: 3.2
11
+ NewCops: enable
12
+ Exclude:
13
+ - node_modules/**/*
14
+ - public/**/*
15
+ - vendor/**/*
16
+
17
+
18
+ RSpec/ContextWording:
19
+ Enabled: false
20
+
21
+ RSpec/DescribeClass:
22
+ Enabled: false
23
+
24
+ RSpec/DescribedClass:
25
+ Enabled: false
26
+
27
+ RSpec/ExampleLength:
28
+ Enabled: false
29
+
30
+ RSpec/ExampleWording:
31
+ Enabled: false
32
+
33
+ RSpec/ExpectInHook:
34
+ Enabled: false
35
+
36
+ RSpec/MessageSpies:
37
+ Enabled: false
38
+
39
+ RSpec/MultipleExpectations:
40
+ Enabled: false
41
+
42
+ RSpec/NamedSubject:
43
+ Enabled: false
44
+
45
+ RSpec/NestedGroups:
46
+ Enabled: false
47
+
48
+ RSpec/StubbedMock:
49
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.9.0
4
+
5
+ - BREAKING CHANGE: Heroku::Configuration has been renamed to HerokuTool::Configuration and is now must be an instance not a class method
6
+ - BREAKING CHANGE: drop set_message for simplicity - you can do that as part of Configuration.before_deploying and Configuration.after_deploying
7
+ - don't continue if git push fails (output AND return status and don't do migration, deployment tracking etc)
8
+
3
9
  ## v0.8.0
4
10
 
5
11
  - allow for multiple databases in configuration
data/README.md CHANGED
@@ -107,11 +107,10 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
107
107
  To install this gem onto your local machine, run `bundle exec rake install`.
108
108
 
109
109
 
110
- Ensure standards before PR:
110
+ Ensure standards (and other rubocop) before PR:
111
111
 
112
- bundle exec standardrb --fix
112
+ bundle exec rubocop -a
113
113
 
114
- (TODO: enforce this or rubocop)
115
114
 
116
115
  ## Release
117
116
 
data/bin/rspec ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("rspec-core", "rspec")
data/bin/rubocop ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("rubocop", "rubocop")
data/heroku_tool.gemspec CHANGED
@@ -27,5 +27,7 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  spec.add_development_dependency "rake", ">= 12.3.3"
29
29
  spec.add_development_dependency "rspec", "~> 3.0"
30
- spec.add_development_dependency "standard", "~> 0.4.1"
30
+ spec.add_development_dependency "standard", "~> 1.52.0"
31
+ spec.add_development_dependency "rubocop", "~> 1.81.7"
32
+ spec.add_development_dependency "rubocop-rspec", "~> 3.8.0"
31
33
  end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HerokuTool
4
+ class Commander
5
+ # @return [HerokuTool::HerokuTargets::HerokuTarget]
6
+ attr_reader :target
7
+ attr_reader :configuration
8
+
9
+ def initialize(target, configuration:, **options)
10
+ @target = target
11
+ @migrate_outside_of_release_phase = target&.migrate_in_release_phase ? false : options[:migrate]
12
+ @configuration = configuration
13
+ end
14
+
15
+ def deploy(deploy_ref, with_maintenance:)
16
+ deploy_ref_description = deploy_ref_describe(deploy_ref)
17
+ puts "Deploy #{deploy_ref_description} to #{target} with migrate=#{target.migrate_in_release_phase ? "(during release phase)" : migrate_outside_of_release_phase?} with_maintenance=#{with_maintenance} "
18
+
19
+ output_to_be_deployed(deploy_ref)
20
+ configuration.before_deploying(self, target, deploy_ref_description)
21
+ successful_push = puts_and_system "git push -f #{target.git_remote} #{deploy_ref || target}^{}:#{target.heroku_target_ref}"
22
+
23
+ return false unless successful_push
24
+
25
+ maintenance_on if with_maintenance
26
+ if migrate_outside_of_release_phase?
27
+ puts_and_system "heroku run rake db:migrate -a #{target.heroku_app}"
28
+ end
29
+
30
+ app_revision_env_var = configuration.app_revision_env_var
31
+ if app_revision_env_var && app_revision_env_var != "HEROKU_SLUG_COMMIT"
32
+ # HEROKU_SLUG_COMMIT is automatically set by https://devcenter.heroku.com/articles/dyno-metadata
33
+ puts_and_system %{heroku config:set #{app_revision_env_var}=$(git describe --always #{deploy_ref}) -a #{target.heroku_app}}
34
+ end
35
+
36
+ maintenance_off if with_maintenance
37
+ configuration.after_deploying(self, target, deploy_ref_description)
38
+ true
39
+ end
40
+
41
+ def maintenance_on
42
+ puts_and_system "heroku maintenance:on -a #{target.heroku_app}"
43
+ puts_and_system "heroku config:set #{configuration.maintenance_mode_env_var}=true -a #{target.heroku_app}"
44
+ end
45
+
46
+ def maintenance_off
47
+ puts_and_system "heroku maintenance:off -a #{target.heroku_app}"
48
+ puts_and_system "heroku config:unset #{configuration.maintenance_mode_env_var} -a #{target.heroku_app}"
49
+ end
50
+
51
+ def migrate_outside_of_release_phase?
52
+ @migrate_outside_of_release_phase
53
+ end
54
+
55
+ def deploy_ref_describe(deploy_ref = nil)
56
+ `git describe #{deploy_ref || target.deploy_ref}`.strip
57
+ end
58
+
59
+ def output_to_be_deployed(since_deploy_ref = nil)
60
+ puts "------------------------------"
61
+ puts " Deploy to #{target}:"
62
+ puts "------------------------------"
63
+ system_with_clean_env "git --no-pager log $(heroku config:get #{configuration.app_revision_env_var} -a #{target.heroku_app})..#{since_deploy_ref || target.deploy_ref}"
64
+ puts "------------------------------"
65
+ end
66
+
67
+ # @return [Boolean] true if the command was successful
68
+ def puts_and_system(cmd)
69
+ puts cmd
70
+ puts "-------------"
71
+ system_with_clean_env(cmd).tap do |result|
72
+ if result
73
+ puts "-------------"
74
+ else
75
+ puts "❌❌❌❌❌❌❌❌❌❌"
76
+ end
77
+ end
78
+ end
79
+
80
+ def puts_and_exec(cmd)
81
+ puts cmd
82
+ exec_with_clean_env(cmd)
83
+ end
84
+
85
+ def exec_with_clean_env(cmd)
86
+ if defined?(Bundler) && Bundler.respond_to?(:with_unbundled_env)
87
+ Bundler.with_unbundled_env { `#{cmd}` }
88
+ elsif defined?(Bundler)
89
+ Bundler.with_clean_env { `#{cmd}` }
90
+ else
91
+ `#{cmd}`
92
+ end
93
+ end
94
+
95
+ protected
96
+
97
+ def system_with_clean_env(cmd)
98
+ if defined?(Bundler) && Bundler.respond_to?(:with_unbundled_env)
99
+ Bundler.with_unbundled_env { system cmd }
100
+ elsif defined?(Bundler)
101
+ Bundler.with_clean_env { system cmd }
102
+ else
103
+ system cmd
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HerokuTool
4
+ class Configuration
5
+ def platform_maintenance_urls(asset_host)
6
+ time = Time.now.strftime("%Y%m%d-%H%M-%S")
7
+ {
8
+ ERROR_PAGE_URL: "https://#{asset_host}/platform_error/#{time}",
9
+ MAINTENANCE_PAGE_URL: "https://#{asset_host}/platform_maintenance/#{time}"
10
+ }
11
+ end
12
+
13
+ def maintenance_mode_env_var
14
+ "X_HEROKU_TOOL_MAINTENANCE_MODE"
15
+ end
16
+
17
+ def app_revision_env_var
18
+ # alternatively if you want you can set this as APP_REVISION (for app-signal) or HEROKU_SLUG_COMMIT (see https://devcenter.heroku.com/articles/dyno-metadata)
19
+ end
20
+
21
+ def before_deploying(_instance, target, version, description: nil)
22
+ puts "about to deploy #{version} to #{target.name}"
23
+ puts " #{description}" if description
24
+ end
25
+
26
+ def after_deploying(_instance, target, version, description: nil)
27
+ puts "deployed #{version} to #{target.name}"
28
+ puts " #{description}" if description
29
+ end
30
+
31
+ def notify_of_deploy_tracking(instance, deploy_ref:, revision:)
32
+ if ENV["BUGSNAG_API_KEY"].present?
33
+ instance.notify_bugsnag_of_deploy_tracking(deploy_ref:, revision:)
34
+ else
35
+ puts "can't notify of deploy tracking: env var not present: BUGSNAG_API_KEY"
36
+ end
37
+ end
38
+
39
+ def after_sync_down(instance)
40
+ # could add source ?
41
+ instance.puts_and_system "rails db:migrate"
42
+ instance.puts_and_system "rails db:test:prepare"
43
+ end
44
+
45
+ def after_sync_to(instance, target)
46
+ # could add source ?
47
+ instance.puts_and_system %(heroku run rails db:migrate -a #{target.heroku_app})
48
+ end
49
+ end
50
+ end
@@ -8,12 +8,12 @@ module HerokuTool
8
8
  @config_all = YAML.safe_load(db_config_from_file, permitted_classes: [], permitted_symbols: [], aliases: true)
9
9
  config_env = @config_all[rails_env]
10
10
  @config_env = if config_env["database"].is_a?(String)
11
- config_env
12
- elsif config_env.key?("primary")
13
- config_env["primary"]
14
- else
15
- config_env.values.first
16
- end
11
+ config_env
12
+ elsif config_env.key?("primary")
13
+ config_env["primary"]
14
+ else
15
+ config_env.values.first
16
+ end
17
17
  end
18
18
 
19
19
  def generate_drop_tables_sql
@@ -29,6 +29,5 @@ module HerokuTool
29
29
  def database
30
30
  config_env["database"]
31
31
  end
32
-
33
32
  end
34
33
  end
@@ -11,7 +11,7 @@ module HerokuTool
11
11
  end
12
12
 
13
13
  def from_file(yaml_file)
14
- new(YAML.safe_load(File.read(yaml_file)))
14
+ new(YAML.safe_load_file(yaml_file))
15
15
  end
16
16
  end
17
17
 
@@ -3,65 +3,35 @@
3
3
  require "thor"
4
4
  require_relative "../db_configuration"
5
5
  require_relative "../heroku_targets"
6
- require_relative "../thor_utils"
6
+ require_relative "../commander"
7
+ require_relative "../configuration"
7
8
 
8
9
  class Heroku < Thor
9
- module Configuration
10
- class << self
11
- def platform_maintenance_urls(asset_host)
12
- time = Time.now.strftime("%Y%m%d-%H%M-%S")
13
- {
14
- ERROR_PAGE_URL: "https://#{asset_host}/platform_error/#{time}",
15
- MAINTENANCE_PAGE_URL: "https://#{asset_host}/platform_maintenance/#{time}"
16
- }
17
- end
18
-
19
- def maintenance_mode_env_var
20
- "X_HEROKU_TOOL_MAINTENANCE_MODE"
21
- end
22
-
23
- def app_revision_env_var
24
- # alternatively if you want you can set this as APP_REVISION (for app-signal) or HEROKU_SLUG_COMMIT (see https://devcenter.heroku.com/articles/dyno-metadata)
25
- end
26
-
27
- def before_deploying(_instance, target, version, description: nil)
28
- puts "about to deploy #{version} to #{target.name}"
29
- puts " #{description}" if description
30
- end
31
-
32
- def after_deploying(_instance, target, version, description: nil)
33
- puts "deployed #{version} to #{target.name}"
34
- puts " #{description}" if description
35
- end
36
-
37
- def notify_of_deploy_tracking(running_thor_task, release_stage:, revision:, revision_describe:, repository:, target:, target_name:, deploy_ref:)
38
- if ENV["BUGSNAG_API_KEY"].present?
39
- running_thor_task.notify_bugsnag_of_deploy_tracking(deploy_ref, release_stage, repository, revision, revision_describe, target_name)
40
- else
41
- puts "can't notify of deploy tracking: env var not present: BUGSNAG_API_KEY"
42
- end
43
- end
44
-
45
- def after_sync_down(instance)
46
- # could add source ?
47
- instance.puts_and_system "rake db:migrate"
48
- instance.puts_and_system "rake db:test:prepare"
49
- end
10
+ namespace "heroku"
11
+ module Shared
12
+ attr_accessor :implied_source
13
+ # @return [HerokuTool::HerokuTarget]
14
+ attr_reader :target
50
15
 
51
- def after_sync_to(instance, target)
52
- # could add source ?
53
- instance.puts_and_system %(heroku run rake db:migrate -a #{target.heroku_app})
54
- end
16
+ # @return [HerokuTool::Commander] commander for target
17
+ def commander
18
+ @commander ||= ::HerokuTool::Commander.new(target, configuration: configuration, **options.symbolize_keys)
55
19
  end
56
- end
57
20
 
58
- module Shared
59
- attr_accessor :implied_source, :implied_target
21
+ def configuration
22
+ ::HerokuTool::Configuration.new
23
+ end
60
24
 
61
- include HerokuTool::ThorUtils
25
+ def self.included(base)
26
+ #:nodoc:
27
+ super
28
+ base.extend ClassMethods
29
+ end
62
30
 
63
- def self.exit_on_failure?
64
- true
31
+ module ClassMethods
32
+ def exit_on_failure?
33
+ true
34
+ end
65
35
  end
66
36
 
67
37
  def lookup_heroku_staging(staging_target_name)
@@ -72,7 +42,7 @@ class Heroku < Thor
72
42
  heroku_targets.targets[target_name] || raise_missing_target(target_name, false)
73
43
  end
74
44
 
75
- def check_deploy_ref(deploy_ref, target = implied_target)
45
+ def check_deploy_ref(deploy_ref)
76
46
  if deploy_ref && deploy_ref[0] == "-"
77
47
  raise Thor::Error, "Invalid deploy ref '#{deploy_ref}'"
78
48
  end
@@ -93,33 +63,13 @@ class Heroku < Thor
93
63
  end
94
64
 
95
65
  def heroku_targets
96
- @heroku_targets ||= HerokuTool::HerokuTargets.from_file(File.expand_path("config/heroku_targets.yml"))
66
+ @heroku_targets ||= ::HerokuTool::HerokuTargets.from_file(File.expand_path("config/heroku_targets.yml"))
97
67
  end
98
68
 
99
69
  protected
100
70
 
101
- def deploy_message(deploy_ref_describe, target = implied_target)
102
- downtime = migrate_outside_of_release_phase?(target) ? "👷 There will be a very short maintenance downtime" : ""
103
- message = <<-DEPLOY_MESSAGE
104
- Deploying #{target.display_name} #{deploy_ref_describe}.
105
- #{downtime} (in less than a minute from now).
106
- DEPLOY_MESSAGE
107
- message.gsub(/(\s|\n)+/, " ")
108
- end
109
-
110
- def migrate_outside_of_release_phase?(target = implied_target)
111
- target.migrate_in_release_phase ? false : options[:migrate]
112
- end
113
-
114
- def maintenance_on(target = implied_target)
115
- puts_and_system "heroku maintenance:on -a #{target.heroku_app}"
116
- puts_and_system "heroku config:set #{Heroku::Configuration.maintenance_mode_env_var}=true -a #{target.heroku_app}"
117
- end
118
-
119
- def maintenance_off(target = implied_target)
120
- puts_and_system "heroku maintenance:off -a #{target.heroku_app}"
121
- puts_and_system "heroku config:unset #{Heroku::Configuration.maintenance_mode_env_var} -a #{target.heroku_app}"
122
- end
71
+ delegate :deploy_ref_describe, :exec_with_clean_env, :maintenance_off, :maintenance_on, :output_to_be_deployed, :migrate_outside_of_release_phase?, :puts_and_exec, :puts_and_system,
72
+ to: :commander
123
73
  end
124
74
 
125
75
  include Shared
@@ -181,41 +131,23 @@ class Heroku < Thor
181
131
  method_option :maintenance, default: nil, desc: "Maintenance step", type: :boolean
182
132
 
183
133
  def deploy(target_name, deploy_ref = nil)
184
- self.implied_target = lookup_heroku(target_name)
185
- deploy_ref = check_deploy_ref(deploy_ref, implied_target)
186
- deploy_ref_description = deploy_ref_describe(deploy_ref)
187
- maintenance = options[:maintenance].nil? && migrate_outside_of_release_phase?(implied_target) || options[:maintenance] || false
188
- puts "Deploy #{deploy_ref_description} to #{implied_target} with migrate=#{implied_target.migrate_in_release_phase ? "(during release phase)" : migrate_outside_of_release_phase?(implied_target)} maintenance=#{maintenance} "
189
-
190
- invoke :list_deployed, [target_name, deploy_ref], {}
191
- message = deploy_message(deploy_ref_description)
192
- Configuration.before_deploying(self, implied_target, deploy_ref_description)
193
- set_message(target_name, message)
194
- puts_and_system "git push -f #{implied_target.git_remote} #{deploy_ref}^{}:#{implied_target.heroku_target_ref}"
195
-
196
- maintenance_on if maintenance
197
- if migrate_outside_of_release_phase?
198
- puts_and_system "heroku run rake db:migrate -a #{implied_target.heroku_app}"
199
- end
200
-
201
-
202
- app_revision_env_var = Heroku::Configuration.app_revision_env_var
203
- if app_revision_env_var && app_revision_env_var != "HEROKU_SLUG_COMMIT"
204
- # HEROKU_SLUG_COMMIT is automatically set by https://devcenter.heroku.com/articles/dyno-metadata
205
- puts_and_system %{heroku config:set #{app_revision_env_var}=$(git describe --always #{deploy_ref}) -a #{implied_target.heroku_app}}
134
+ @target = lookup_heroku(target_name)
135
+ check_deploy_ref(deploy_ref)
136
+ with_maintenance = options[:maintenance].nil? && migrate_outside_of_release_phase? || options[:maintenance] || false
137
+ deploy_ref ||= target.deploy_ref
138
+ success = commander.deploy(deploy_ref, with_maintenance: with_maintenance)
139
+ if success
140
+ deploy_tracking(target_name, deploy_ref)
141
+ else
142
+ exit(-1)
206
143
  end
207
-
208
- maintenance_off if maintenance
209
- set_message(target_name, nil)
210
- Configuration.after_deploying(self, implied_target, deploy_ref_description)
211
- deploy_tracking(target_name, deploy_ref)
212
144
  end
213
145
 
214
146
  desc "maintenance ON|OFF", "turn maintenance mode on or off"
215
147
  method_option :target_name, aliases: "a", desc: "Target (app or remote)"
216
148
 
217
149
  def maintenance(on_or_off)
218
- self.implied_target = lookup_heroku(options[:target_name])
150
+ @target = lookup_heroku(options[:target_name])
219
151
  case on_or_off.upcase
220
152
  when "ON"
221
153
  maintenance_on
@@ -229,45 +161,46 @@ class Heroku < Thor
229
161
  desc "set_urls TARGET", "set and cache the error and maintenance page urls for TARGET"
230
162
 
231
163
  def set_urls(target_name)
232
- self.implied_target = lookup_heroku(target_name)
164
+ @target = lookup_heroku(target_name)
233
165
  unless asset_host.presence
234
- puts "asset host (ASSET_HOST) not found on #{implied_target.heroku_app}"
166
+ puts "asset host (ASSET_HOST) not found on #{target.heroku_app}"
235
167
  return
236
168
  end
237
- url_hash = Configuration.platform_maintenance_urls(asset_host)
169
+ url_hash = configuration.platform_maintenance_urls(asset_host)
238
170
  url_hash.each do |_env, url|
239
171
  puts_and_system "open #{url}"
240
172
  end
241
173
  puts_and_system(
242
- "heroku config:set #{url_hash.map { |e, u| "#{e}=#{u}" }.join(" ")} -a #{implied_target.heroku_app}"
174
+ "heroku config:set #{url_hash.map { |e, u| "#{e}=#{u}" }.join(" ")} -a #{target.heroku_app}"
243
175
  )
244
176
  end
245
177
 
246
178
  no_commands do
247
- def asset_host(target = implied_target)
248
- if target == implied_target
249
- @asset_host ||= fetch_asset_host(target)
250
- else
251
- fetch_asset_host(target)
252
- end
179
+ def asset_host
180
+ @asset_host ||= fetch_asset_host
253
181
  end
254
182
 
255
183
  def get_config_env(target, env_var)
256
184
  puts_and_exec("heroku config:get #{env_var} -a #{target.heroku_app}").strip.presence
257
185
  end
258
186
 
259
- def deploy_ref_describe(deploy_ref)
260
- `git describe #{deploy_ref}`.strip
187
+ def notify_of_deploy_tracking(deploy_ref)
188
+ revision = `git log -1 #{deploy_ref || target.deploy_ref} --pretty=format:%H`
189
+ configuration.notify_of_deploy_tracking(
190
+ self,
191
+ deploy_ref: deploy_ref,
192
+ revision: revision
193
+ )
261
194
  end
262
195
 
263
- def notify_bugsnag_of_deploy_tracking(deploy_ref, release_stage, repository, revision, revision_describe, target_name)
196
+ def notify_bugsnag_of_deploy_tracking(deploy_ref:, revision:)
264
197
  api_key = ENV["BUGSNAG_API_KEY"]
265
198
  data = %W[
266
199
  apiKey=#{api_key}
267
- releaseStage=#{release_stage}
268
- repository=#{repository}
200
+ releaseStage=#{target.trackable_release_stage}
201
+ repository=#{target.repository}
269
202
  revision=#{revision}
270
- appVersion=#{revision_describe}
203
+ appVersion=#{deploy_ref_describe(deploy_ref)}
271
204
  ].join("&")
272
205
  if api_key.blank?
273
206
  puts "\n" + ("*" * 80) + "\n"
@@ -275,7 +208,7 @@ class Heroku < Thor
275
208
  puts command
276
209
  puts "\n" + ("*" * 80) + "\n"
277
210
  puts "NB: can't notify unless you specify BUGSNAG_API_KEY and rerun"
278
- puts " thor heroku:deploy_tracking #{target_name} #{deploy_ref}"
211
+ puts " thor heroku:deploy_tracking #{target.name} #{deploy_ref}"
279
212
  else
280
213
  puts_and_system "curl -d \"#{data}\" http://notify.bugsnag.com/deploy"
281
214
  end
@@ -285,42 +218,27 @@ class Heroku < Thor
285
218
  desc "deploy_tracking TARGET (REF)", "set deploy tracking for TARGET and REF (used by deploy)"
286
219
 
287
220
  def deploy_tracking(target_name, deploy_ref = nil)
288
- self.implied_target = lookup_heroku(target_name)
289
- deploy_ref = check_deploy_ref(deploy_ref)
290
- revision = `git log -1 #{deploy_ref} --pretty=format:%H`
291
- Heroku::Configuration.notify_of_deploy_tracking(
292
- self,
293
- deploy_ref: deploy_ref,
294
- release_stage: implied_target.trackable_release_stage,
295
- revision: revision,
296
- target: implied_target,
297
- target_name: target_name,
298
- revision_describe: deploy_ref_describe(deploy_ref),
299
- repository: implied_target.repository
300
- )
221
+ @target = lookup_heroku(target_name)
222
+ check_deploy_ref(deploy_ref)
223
+ notify_of_deploy_tracking(deploy_ref)
301
224
  end
302
225
 
303
- include HerokuTool::ThorUtils
304
226
  desc "set_message TARGET (MESSAGE)", "set message (no-op by default)"
305
227
 
306
228
  def set_message(target_name, message = nil)
307
229
  # no-op -- define as override
308
230
  end
309
231
 
310
- desc "list_deployed TARGET (DEPLOY_REF)", "list what would be deployed to TARGET (optionally specify deploy_ref)"
232
+ desc "to_be_deployed TARGET (SINCE_DEPLOY_REF)", "list what would be deployed to TARGET (optionally specify SINCE_DEPLOY_REF)"
311
233
 
312
- def list_deployed(target_name, deploy_ref = nil)
313
- if Heroku::Configuration.app_revision_env_var.nil?
314
- puts "Can't list deployed as Heroku::Configuration.app_revision_env_var is not set"
234
+ def to_be_deployed(target_name, since_deploy_ref = nil)
235
+ if configuration.app_revision_env_var.nil?
236
+ puts "Can't list deployed as Configuration.app_revision_env_var is not set"
315
237
  return
316
238
  end
317
- self.implied_target = lookup_heroku(target_name)
318
- deploy_ref = check_deploy_ref(deploy_ref)
319
- puts "------------------------------"
320
- puts " Deploy to #{implied_target}:"
321
- puts "------------------------------"
322
- system_with_clean_env "git --no-pager log $(heroku config:get #{Heroku::Configuration.app_revision_env_var} -a #{implied_target.heroku_app})..#{deploy_ref}"
323
- puts "------------------------------"
239
+ @target = lookup_heroku(target_name)
240
+ check_deploy_ref(since_deploy_ref)
241
+ output_to_be_deployed(since_deploy_ref)
324
242
  end
325
243
 
326
244
  desc "about (TARGET)", "Describe available targets or one specific target"
@@ -332,19 +250,21 @@ class Heroku < Thor
332
250
  puts " * #{key} (#{target})"
333
251
  end
334
252
  else
335
- self.implied_target = lookup_heroku(target_name)
253
+ @target = lookup_heroku(target_name)
336
254
  puts "Target #{target_name}:"
337
- puts " * display_name: #{implied_target.display_name}"
338
- puts " * heroku_app: #{implied_target.heroku_app}"
339
- puts " * git_remote: #{implied_target.git_remote}"
340
- puts " * deploy_ref: #{implied_target.deploy_ref}"
255
+ puts " * display_name: #{target.display_name}"
256
+ puts " * heroku_app: #{target.heroku_app}"
257
+ puts " * git_remote: #{target.git_remote}"
258
+ puts " * deploy_ref: #{target.deploy_ref}"
341
259
  end
342
260
  puts
343
261
  puts "(defined in config/heroku_targets.yml)"
344
262
  end
345
263
 
346
264
  class Sync < Thor
265
+ namespace "heroku:db"
347
266
  include Shared
267
+
348
268
  class_option :from, type: :string, desc: "source target (production, staging...)", required: true, aliases: "f"
349
269
 
350
270
  desc "down --from SOURCE_TARGET", "syncs db down from SOURCE_TARGET | thor heroku:sync -f production"
@@ -391,9 +311,9 @@ class Heroku < Thor
391
311
  def from_dump
392
312
  invoke "warn", [], from: options[:from]
393
313
  source = lookup_heroku(options[:from])
394
- db_config = HerokuTool::DbConfiguration.new
314
+ db_config = ::HerokuTool::DbConfiguration.new
395
315
  puts_and_system "pg_restore --verbose --clean --no-acl --no-owner -h localhost #{db_config.user_arg} -d #{db_config.database} #{source.dump_filename}"
396
- Configuration.after_sync_down(self) unless options[:just_restore]
316
+ configuration.after_sync_down(self) unless options[:just_restore]
397
317
  end
398
318
 
399
319
  desc "dump_to_tmp", "dump to tmp directory"
@@ -407,15 +327,15 @@ class Heroku < Thor
407
327
  desc "to STAGING_TARGET --from=SOURCE_TARGET", "push db onto STAGING_TARGET from SOURCE_TARGET"
408
328
 
409
329
  def to(to_target_name)
410
- self.implied_target = lookup_heroku_staging(to_target_name)
330
+ @target = lookup_heroku_staging(to_target_name)
411
331
  self.implied_source = lookup_heroku(options[:from])
412
332
 
413
- maintenance_on # target, not source
333
+ maintenance_on
414
334
 
415
335
  puts_and_system %(
416
- heroku pg:copy #{implied_source.heroku_app}::#{implied_source.db_color} #{implied_target.db_color} -a #{implied_target.heroku_app} --confirm #{implied_target.heroku_app}
336
+ heroku pg:copy #{implied_source.heroku_app}::#{implied_source.db_color} #{target.db_color} -a #{target.heroku_app} --confirm #{target.heroku_app}
417
337
  )
418
- Configuration.after_sync_to(self, implied_target) unless options[:just_copy]
338
+ configuration.after_sync_to(self, target) unless options[:just_copy]
419
339
  maintenance_off
420
340
  end
421
341
 
@@ -424,7 +344,7 @@ class Heroku < Thor
424
344
  def dump_local(dumpfilepath)
425
345
  puts "dumping postgres to #{dumpfilepath}"
426
346
  rails_env = ENV["RAILS_ENV"] || "development"
427
- db_config = HerokuTool::DbConfiguration.new.config[rails_env]
347
+ db_config = ::HerokuTool::DbConfiguration.new.config[rails_env]
428
348
  db_username = db_config["username"]
429
349
  db = db_config["database"]
430
350
  system_with_clean_env "pg_dump --verbose --clean --no-acl --no-owner -h localhost -U #{db_username} --format=c #{db} > #{dumpfilepath}"
@@ -432,36 +352,37 @@ class Heroku < Thor
432
352
  end
433
353
 
434
354
  class Db < Thor
355
+ namespace "heroku:db"
435
356
  include Shared
436
357
 
437
358
  desc "drop_all_tables on STAGING_TARGET", "drop all tables on STAGING_TARGET"
438
359
 
439
360
  def drop_all_tables(staging_target_name)
440
- self.implied_target = lookup_heroku_staging(staging_target_name)
441
- generate_drop_tables_sql = `#{HerokuTool::DbConfiguration.new.generate_drop_tables_sql}`
442
- cmd_string = %(heroku pg:psql -a #{implied_target.heroku_app} -c "#{generate_drop_tables_sql}")
361
+ @target = lookup_heroku_staging(staging_target_name)
362
+ generate_drop_tables_sql = `#{::HerokuTool::DbConfiguration.new.generate_drop_tables_sql}`
363
+ cmd_string = %(heroku pg:psql -a #{target.heroku_app} -c "#{generate_drop_tables_sql}")
443
364
  puts_and_system(cmd_string)
444
365
  end
445
366
 
446
367
  desc "anonymize STAGING_TARGET", "run anonymization scripts on STAGING_TARGET"
447
368
 
448
369
  def anonymize(staging_target_name)
449
- self.implied_target = lookup_heroku_staging(staging_target_name)
370
+ @target = lookup_heroku_staging(staging_target_name)
450
371
  puts_and_system %(
451
- heroku run rake data:anonymize -a #{implied_target.heroku_app}
372
+ heroku run rake data:anonymize -a #{target.heroku_app}
452
373
  )
453
374
  end
454
375
  end
455
376
 
456
377
  private
457
378
 
458
- def fetch_asset_host(target)
379
+ def fetch_asset_host
459
380
  get_config_env(target, "ASSET_HOST")
460
381
  end
461
382
 
462
383
  def print_output_progress(remote_targets, index = nil)
463
384
  index ||= remote_targets.length
464
385
  remainder = remote_targets.length - index
465
- print "\routputting configs to tmp/config.*.txt: #{index}/#{remote_targets.count} ▕#{'██' * index}#{" " * remainder}▏\r"
386
+ print "\routputting configs to tmp/config.*.txt: #{index}/#{remote_targets.count} ▕#{"██" * index}#{" " * remainder}▏\r"
466
387
  end
467
388
  end
@@ -1,3 +1,3 @@
1
1
  module HerokuTool
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -49,6 +49,14 @@ class Heroku
49
49
  # def after_deploying(instance, target, version)
50
50
  # # override
51
51
  # end
52
+ #
53
+ # def before_deploying(instance, target, version)
54
+ # # override
55
+ # end
56
+ #
57
+ # def after_deploying(instance, target, version)
58
+ # # override
59
+ # end
52
60
  end
53
61
 
54
62
  module Configuration
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heroku_tool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Diggins
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-09-03 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: thor
@@ -86,24 +85,52 @@ dependencies:
86
85
  requirements:
87
86
  - - "~>"
88
87
  - !ruby/object:Gem::Version
89
- version: 0.4.1
88
+ version: 1.52.0
90
89
  type: :development
91
90
  prerelease: false
92
91
  version_requirements: !ruby/object:Gem::Requirement
93
92
  requirements:
94
93
  - - "~>"
95
94
  - !ruby/object:Gem::Version
96
- version: 0.4.1
97
- description:
95
+ version: 1.52.0
96
+ - !ruby/object:Gem::Dependency
97
+ name: rubocop
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 1.81.7
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 1.81.7
110
+ - !ruby/object:Gem::Dependency
111
+ name: rubocop-rspec
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: 3.8.0
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: 3.8.0
98
124
  email:
99
125
  - tim@fieldnotescommunities.com
100
126
  executables: []
101
127
  extensions: []
102
128
  extra_rdoc_files: []
103
129
  files:
130
+ - ".github/workflows/main.yml"
104
131
  - ".gitignore"
105
132
  - ".rspec"
106
- - ".travis.yml"
133
+ - ".rubocop.yml"
107
134
  - CHANGELOG.md
108
135
  - CODE_OF_CONDUCT.md
109
136
  - Gemfile
@@ -111,14 +138,17 @@ files:
111
138
  - README.md
112
139
  - Rakefile
113
140
  - bin/console
141
+ - bin/rspec
142
+ - bin/rubocop
114
143
  - bin/setup
115
144
  - heroku_tool.gemspec
116
145
  - lib/heroku_tool.rb
146
+ - lib/heroku_tool/commander.rb
147
+ - lib/heroku_tool/configuration.rb
117
148
  - lib/heroku_tool/db_configuration.rb
118
149
  - lib/heroku_tool/heroku_targets.rb
119
150
  - lib/heroku_tool/tasks/db_drop_all_tables.rake
120
151
  - lib/heroku_tool/tasks/heroku.thor
121
- - lib/heroku_tool/thor_utils.rb
122
152
  - lib/heroku_tool/version.rb
123
153
  - templates/Rakefile
124
154
  - templates/heroku.thor
@@ -127,7 +157,6 @@ homepage: https://github.com/fieldnotescommunities/heroku_tool
127
157
  licenses:
128
158
  - MIT
129
159
  metadata: {}
130
- post_install_message:
131
160
  rdoc_options: []
132
161
  require_paths:
133
162
  - lib
@@ -142,8 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
171
  - !ruby/object:Gem::Version
143
172
  version: '0'
144
173
  requirements: []
145
- rubygems_version: 3.5.15
146
- signing_key:
174
+ rubygems_version: 3.6.9
147
175
  specification_version: 4
148
176
  summary: Tool for configurable one-shot deployment and db managment with heroku and
149
177
  rails
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.5.7
7
- before_install: gem install bundler -v 1.17.3
@@ -1,37 +0,0 @@
1
- module HerokuTool
2
- module ThorUtils
3
- def puts_and_system(cmd)
4
- puts cmd
5
- puts "-------------"
6
- system_with_clean_env cmd
7
- puts "-------------"
8
- end
9
-
10
- protected
11
-
12
- def puts_and_exec(cmd)
13
- puts cmd
14
- exec_with_clean_env(cmd)
15
- end
16
-
17
- def system_with_clean_env(cmd)
18
- if defined?(Bundler) && Bundler.respond_to?(:with_unbundled_env)
19
- Bundler.with_unbundled_env { system cmd }
20
- elsif defined?(Bundler)
21
- Bundler.with_clean_env { system cmd }
22
- else
23
- system cmd
24
- end
25
- end
26
-
27
- def exec_with_clean_env(cmd)
28
- if defined?(Bundler) && Bundler.respond_to?(:with_unbundled_env)
29
- Bundler.with_unbundled_env { `#{cmd}` }
30
- elsif defined?(Bundler)
31
- Bundler.with_clean_env { `#{cmd}` }
32
- else
33
- `#{cmd}`
34
- end
35
- end
36
- end
37
- end