deploy_pin 1.6.0 → 1.7.1

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: 7ebbfe96a88deeb425d7b53e1c3a99cda696fac889f80cb333bb912afe2ceba1
4
- data.tar.gz: 2bda5afc250a357af2637cd950d3ed1f0362b0f32d2cf65782fe12081b88eca0
3
+ metadata.gz: 231084c3af2dd8f819d5ff7acb16a870a82a184065bf061ec68cebd49870e2cf
4
+ data.tar.gz: e5137be3496284aeb4da5249860fb64f608ee5bd130203658536d834b943e68f
5
5
  SHA512:
6
- metadata.gz: 2171f9ae37344e3fb589e99804362df12182fc1cae478b165d3d9f6d1c90b7ef86c5b34d2e099f22a5f168fbeca6e489de6526542f844edd029414fdb285f273
7
- data.tar.gz: 734b7f41d25fc84abaff5e81e00c477ff382854e3175581113c967f758d5e31317d56710dbeeabf4bf198e6a27c11e96a5f678f62c4b97d8878261abbd1ded63
6
+ metadata.gz: 0ba193060689f387db8cfc77dca413dec40e781c7540abd2c63b887dbf023b57993678e51859b16d80dd344febbc7662ec5b58cf8eb74b8a2bcd53a8a4e11c9b
7
+ data.tar.gz: b7b54e4e70559aff8aaa2f7d40d208a8194802d412c4dd186aa411763eb560b36e2fd221251c8fb460e8f148546fca7d2b73995dcd2708f6ff2fcaed0d373065
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2019 rafael
1
+ Copyright 2019 Viktor Sych
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -176,6 +176,27 @@ end
176
176
 
177
177
  To use a different formatting value than the default, you need to specify it explicitly in the task, similar to the database timeout configuration.
178
178
 
179
+ ## Resumable Tasks
180
+
181
+ When working with long-running code that processes a large dataset, it makes sense to store progress in the database to allow resuming the task later. You can do this by using the `DeployPin::Task` instance methods: `#progress` and `#increment_progress(num)`.
182
+
183
+ Here is an example of how to use these methods:
184
+
185
+ ```ruby
186
+ # Some DeployPin task
187
+ ...
188
+ # === task code goes here ===
189
+
190
+ # The progress is 0 by default
191
+ Users.where(id: progress..).find_each do |user|
192
+ # Do some work
193
+ increment_progress(1) # Increment progress by 1 and store it in the database so you can resume the task from this point
194
+ end
195
+ ```
196
+
197
+ This allows your task to resume from where it left off, minimizing the risk of repeating work.
198
+
199
+
179
200
  ## Recurring Tasks
180
201
  If you want to generate a recurring task, you can use the `--recurring` option. Make sure to set a correct `--identifier`, which should be a numeric value. Positive and negative numbers are possible here. The identifier affects the order of task execution, allowing you to customize the sequence as desired.
181
202
 
@@ -212,6 +233,8 @@ bundle exec rake deploy_pin:run[I, II, III] - # enters to ongoing state before "
212
233
  bundle exec rake deploy_pin:run[rollback] - # enters "pending state"
213
234
  ```
214
235
  ## Similar Gems
236
+ - https://github.com/ilyakatz/data-migrate
237
+ - https://github.com/Shopify/maintenance_tasks
215
238
  - https://github.com/theSteveMitchell/after_party
216
239
 
217
240
  ## Contributing
@@ -12,50 +12,51 @@ module DeployPin
12
12
  # :reek:TooManyStatements
13
13
  def run
14
14
  # cache tasks
15
- _tasks = tasks
16
- _tasks.each_with_index do |task, index|
17
- DeployPin.task_wrapper.call(task, -> { process(_tasks, task, index) })
15
+ tasks = init_tasks
16
+ tasks.each_with_index do |task, index|
17
+ DeployPin.task_wrapper.call(task, -> { process(tasks, task, index) })
18
18
  end
19
19
  end
20
20
  # :reek:TooManyStatements
21
21
 
22
22
  def list
23
- _tasks = tasks
24
- _tasks.each_with_index do |task, index|
23
+ tasks = init_tasks
24
+ tasks.each_with_index do |task, index|
25
25
  DeployPin.list_formatter.call(index, task)
26
26
  end
27
27
  end
28
28
 
29
29
  def executable
30
30
  # cache tasks
31
- _tasks = tasks
32
- _tasks.map.with_index do |task, index|
33
- task if _tasks[0..index].none? { |_task| task.eql?(_task) }
31
+ tasks = init_tasks
32
+ tasks.map.with_index do |task, index|
33
+ task if tasks[0..index].none? { |other_task| task.eql?(other_task) }
34
34
  end.compact
35
35
  end
36
36
 
37
37
  def tasks_count
38
- tasks.count
38
+ init_tasks.count
39
39
  end
40
40
 
41
41
  private
42
42
 
43
43
  # :reek:FeatureEnvy
44
44
  # :reek:TooManyStatements
45
- def process(cached_tasks, task, index)
45
+ def process(tasks, task, index)
46
46
  # run only uniq tasks
47
- executable = cached_tasks[0..index].none? { |_task| task.eql?(_task) }
47
+ executable = tasks[0..index].none? { |other_task| task.eql?(other_task) }
48
48
 
49
- DeployPin.run_formatter.call(index, cached_tasks.count, task, executable, true)
49
+ DeployPin.run_formatter.call(index, tasks.count, task, executable, true)
50
+
51
+ task.prepare
50
52
 
51
53
  # run if executable
52
54
  if executable
53
55
  duration = execution_duration { run_with_timeout(task) { task.run } }
54
- DeployPin.run_formatter.call(index, cached_tasks.count, task, executable, false, duration)
56
+ DeployPin.run_formatter.call(index, tasks.count, task, executable, false, duration)
55
57
  end
56
58
 
57
- # mark each task as done
58
- task.mark unless task.done?
59
+ task.mark # mark each task as done
59
60
  end
60
61
  # :reek:TooManyStatements
61
62
  # :reek:FeatureEnvy
@@ -65,7 +66,7 @@ module DeployPin
65
66
  Dir["#{DeployPin.tasks_path}/*.rb"]
66
67
  end
67
68
 
68
- def tasks
69
+ def init_tasks
69
70
  [*DeployPin.deployment_tasks_code, *files].map do |file|
70
71
  task = DeployPin::Task.new(file)
71
72
  task.parse
@@ -76,7 +77,7 @@ module DeployPin
76
77
  end
77
78
 
78
79
  def task_criteria
79
- @task_criteria ||= DeployPin::TaskCriteria.new(identifiers: identifiers)
80
+ @task_criteria ||= DeployPin::TaskCriteria.new(identifiers:)
80
81
  end
81
82
 
82
83
  # :reek:UtilityFunction and :reek:ControlParameter
@@ -4,17 +4,17 @@
4
4
  module DeployPin
5
5
  module Runner
6
6
  def self.run(identifiers:)
7
- DeployPin::Collector.new(identifiers: identifiers).run
7
+ DeployPin::Collector.new(identifiers:).run
8
8
  end
9
9
 
10
10
  def self.list(identifiers:)
11
- DeployPin::Collector.new(identifiers: identifiers).list
11
+ DeployPin::Collector.new(identifiers:).list
12
12
  end
13
13
 
14
14
  def self.summary(identifiers:)
15
15
  # print summary
16
16
  self.print('======= Summary ========')
17
- self.print("Tasks number: #{DeployPin::Collector.new(identifiers: identifiers).tasks_count}")
17
+ self.print("Tasks number: #{DeployPin::Collector.new(identifiers:).tasks_count}")
18
18
  end
19
19
 
20
20
  def self.print(msg)
@@ -14,6 +14,8 @@ module DeployPin
14
14
  :recurring,
15
15
  :explicit_timeout
16
16
 
17
+ delegate :progress, to: :record
18
+
17
19
  def initialize(file)
18
20
  @file = file
19
21
  @identifier = nil
@@ -29,17 +31,34 @@ module DeployPin
29
31
  eval(script)
30
32
  end
31
33
 
34
+ def record
35
+ DeployPin::Record.find_by(uuid: identifier)
36
+ end
37
+
38
+ def prepare
39
+ return if recurring
40
+
41
+ DeployPin::Record.create(uuid: identifier) unless record
42
+ end
43
+
32
44
  def mark
33
45
  return if recurring
34
46
 
35
47
  # store record in the DB
36
- DeployPin::Record.create(uuid: identifier)
48
+ record.update(completed_at: Time.current)
49
+ end
50
+
51
+ def increment_progress!(incrementor)
52
+ raise NotImplementedError, 'Recurring tasks do not support progress yet.' if recurring
53
+
54
+ record.increment!(:progress, incrementor)
37
55
  end
38
56
 
39
57
  def done?
40
58
  return if recurring
59
+ return unless record
41
60
 
42
- DeployPin::Record.where(uuid: identifier).exists?
61
+ record.completed_at.present?
43
62
  end
44
63
 
45
64
  def under_timeout?
@@ -74,9 +93,9 @@ module DeployPin
74
93
 
75
94
  def details
76
95
  {
77
- identifier: identifier,
78
- group: group,
79
- title: title
96
+ identifier:,
97
+ group:,
98
+ title:
80
99
  }
81
100
  end
82
101
 
@@ -104,7 +123,6 @@ module DeployPin
104
123
 
105
124
  protected
106
125
 
107
-
108
126
  def group_index
109
127
  DeployPin.groups.index(group)
110
128
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeployPin
4
- VERSION = '1.6.0'
4
+ VERSION = '1.7.1'
5
5
  end
@@ -4,6 +4,8 @@ class CreateDeployPins < ActiveRecord::Migration[7.0]
4
4
  def change
5
5
  create_table :deploy_pins do |t|
6
6
  t.string :uuid
7
+ t.integer :progress, default: 0
8
+ t.datetime :completed_at, default: nil
7
9
  t.timestamps
8
10
  end
9
11
  end
@@ -6,11 +6,11 @@ DeployPin.setup do
6
6
  fallback_group 'III'
7
7
  statement_timeout 10.minutes
8
8
  deployment_state_transition({
9
- ongoing: %w[I III],
10
- pending: 'rollback', # enters to pending step before "rollback"
11
- ttl: 20.second, # memoize the state to avoid the store spam
12
- redis_url: 'redis://localhost:6379'
13
- })
9
+ ongoing: %w[I III],
10
+ pending: 'rollback', # enters to pending step before "rollback"
11
+ ttl: 20.second, # memoize the state to avoid the store spam
12
+ redis_url: 'redis://localhost:6379'
13
+ })
14
14
  run_formatter(
15
15
  lambda do |index, task_count, task, executable, start, duration = nil|
16
16
  end_of_msg = if executable
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Upgrades the deploy_pins table in the DB with an extra columns for resumable tasks
3
+
4
+ Example:
5
+ rails generate deploy_pin:upgrade
6
+
7
+ This will create:
8
+ db/migrate/upgrade_deploy_pins.rb
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UpgradeDeployPins < ActiveRecord::Migration[7.0]
4
+ def change
5
+ add_column :deploy_pins, :progress, :integer, default: 0, if_not_exists: true
6
+ add_column :deploy_pins, :completed_at, :datetime, default: nil, if_not_exists: true
7
+
8
+ # set completed_at to created_at for all completed deploy_pins
9
+ DeployPin::Record.update_all('completed_at = created_at')
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeployPin
4
+ # This generator is used to generate the migration file for upgrading db schema for 1.7 version support.
5
+ class UpgradeGenerator < Rails::Generators::Base
6
+ include Rails::Generators::Migration
7
+
8
+ source_root File.expand_path('templates', __dir__)
9
+ desc 'Add the upgrade migration for DeployPin.'
10
+
11
+ def self.next_migration_number(path)
12
+ next_migration_number = current_migration_number(path) + 1
13
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
14
+ end
15
+
16
+ def copy_migrations
17
+ migration_template 'upgrade_deploy_pins.rb', 'db/migrate/upgrade_deploy_pins.rb'
18
+ end
19
+ end
20
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deploy_pin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Viktor Sych
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-07 00:00:00.000000000 Z
11
+ date: 2024-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -251,6 +251,9 @@ files:
251
251
  - lib/generators/deploy_pin/task/task_generator.rb
252
252
  - lib/generators/deploy_pin/task/templates/parallel_task.rb.erb
253
253
  - lib/generators/deploy_pin/task/templates/task.rb.erb
254
+ - lib/generators/deploy_pin/upgrade/USAGE
255
+ - lib/generators/deploy_pin/upgrade/templates/upgrade_deploy_pins.rb
256
+ - lib/generators/deploy_pin/upgrade/upgrade_generator.rb
254
257
  - lib/tasks/deploy_pin_tasks.rake
255
258
  homepage: https://github.com/skcc321/deploy_pin
256
259
  licenses:
@@ -265,7 +268,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
265
268
  requirements:
266
269
  - - ">="
267
270
  - !ruby/object:Gem::Version
268
- version: '3.0'
271
+ version: '3.1'
269
272
  required_rubygems_version: !ruby/object:Gem::Requirement
270
273
  requirements:
271
274
  - - ">="