deploy_pin 1.4.0 → 1.5.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 +4 -4
- data/README.md +77 -51
- data/lib/deploy_pin/collector.rb +2 -2
- data/lib/deploy_pin/database.rb +1 -0
- data/lib/deploy_pin/deployment_state.rb +102 -0
- data/lib/deploy_pin/task.rb +42 -15
- data/lib/deploy_pin/task_criteria.rb +4 -4
- data/lib/deploy_pin/version.rb +1 -1
- data/lib/deploy_pin.rb +13 -1
- data/lib/generators/deploy_pin/install/templates/create_deploy_pins.rb +1 -1
- data/lib/generators/deploy_pin/install/templates/deploy_pin.rb +9 -3
- data/lib/generators/deploy_pin/task/task_generator.rb +7 -3
- data/lib/generators/deploy_pin/task/templates/parallel_task.rb.erb +2 -1
- data/lib/generators/deploy_pin/task/templates/task.rb.erb +2 -1
- metadata +48 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c21646b048b09408bf131ab463208e76dd54b18596dcdfce4c16fae3fa1669f1
|
4
|
+
data.tar.gz: 5ac45e42ba5a3af95dadbf44031e683997f8fe42a8e422f1d7114f5007437e8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6137f6270259681a0a74188e1a0145894d25eb77bde43d8ed47b9dea38c1ab7733ca618b44ac04d15e6ebbaf3f565200cb09af3ee91e8f9b2fca756ee9c5c250
|
7
|
+
data.tar.gz: 8551c4fadd20f97cd19584566408a115d42a9402b45b46fba4c4fdf6e94b3f1b9b074136287b814ca3ff1603bfe77b5fa51bbc9814fcdf1ef59f421dd6052025
|
data/README.md
CHANGED
@@ -1,123 +1,125 @@
|
|
1
|
+
[](https://opensource.org/licenses/MIT)
|
1
2
|
[](https://badge.fury.io/rb/deploy_pin)
|
2
3
|

|
3
|
-
](https://github.com/skcc321/deploy_pin/actions/workflows/verify.yml)
|
5
|
+
[](https://github.com/skcc321/deploy_pin/actions/workflows/publish.yml)
|
4
6
|
|
5
7
|
# DeployPin
|
6
8
|
|
7
9
|

|
8
10
|
|
9
|
-
|
10
|
-
Most likely you use migrations for such things, but that is not what is related to migration at all.
|
11
|
-
Also sometimes you need to execute some code before migration or later, after migration without blocking of main thread.
|
11
|
+
Deploying applications often involves the need to execute a series of specific commands or tasks either before or after the deployment process. While you might typically turn to migrations for such operations, these tasks aren't always migration-related. Additionally, there are situations where you need to execute code before or after a migration without causing the main thread to block.
|
12
12
|
|
13
|
-
deploy_pins
|
13
|
+
Introducing deploy_pins – your go-to solution for streamlined task management during the deployment process. This Ruby library allows you to seamlessly orchestrate tasks before, after, or independently of migrations, offering the flexibility you need to maintain a smooth and efficient deployment workflow. With deploy_pins, you can take control of your deployment tasks and ensure that your application operates flawlessly in any environment.
|
14
14
|
|
15
15
|
## Usage
|
16
16
|
|
17
|
-
|
18
17
|

|
19
18
|
|
20
|
-
To generate new task template file
|
19
|
+
To generate a new task template file:
|
21
20
|
```bash
|
22
21
|
rails g deploy_pin:task some_task_title
|
23
22
|
# or
|
24
23
|
rails g deploy_pin:task some_task_title --parallel
|
25
24
|
```
|
26
25
|
|
27
|
-
|
26
|
+
You can also specify the author:
|
28
27
|
```bash
|
29
28
|
rails g deploy_pin:task some_task_title -a author_name
|
30
29
|
```
|
31
30
|
|
32
|
-
To list all pending tasks
|
31
|
+
To list all pending tasks:
|
33
32
|
```bash
|
34
33
|
rake deploy_pin:list
|
35
34
|
```
|
36
35
|
|
37
|
-
To run all pending tasks
|
36
|
+
To run all pending tasks:
|
38
37
|
```bash
|
39
38
|
rake deploy_pin:run
|
40
39
|
```
|
41
40
|
|
42
|
-
##
|
41
|
+
## Grouped Tasks
|
43
42
|
|
44
|
-
|
45
|
-
if you want to group tasks around "allowed_group"
|
43
|
+
To define allowed groups, navigate to `config/initializers/deploy_pin.rb`. You can group tasks around the "allowed_group" like this:
|
46
44
|
```bash
|
47
45
|
rails g deploy_pin:task task_title -g allowed_group
|
48
46
|
# or
|
49
47
|
rails g deploy_pin:task task_title -g allowed_group --parallel
|
50
48
|
```
|
51
49
|
|
52
|
-
To list all pending tasks
|
50
|
+
To list all pending tasks within the "allowed_group":
|
53
51
|
```bash
|
54
52
|
rake deploy_pin:list[allowed_group]
|
55
53
|
```
|
56
54
|
|
57
|
-
To run all pending tasks
|
55
|
+
To run all pending tasks within the "allowed_group":
|
58
56
|
```bash
|
59
57
|
rake deploy_pin:run[allowed_group]
|
60
58
|
```
|
61
59
|
|
62
|
-
## Run by
|
60
|
+
## Run by Identifier
|
63
61
|
|
64
|
-
To
|
62
|
+
To execute a specific task using its identifier:
|
65
63
|
```bash
|
66
|
-
rake deploy_pin:run['
|
64
|
+
rake deploy_pin:run['identifier_1, identifier_2']
|
67
65
|
```
|
68
|
-
|
66
|
+
|
67
|
+
Alternatively, you can combine an identifier and a group:
|
69
68
|
```bash
|
70
|
-
rake deploy_pin:run['
|
69
|
+
rake deploy_pin:run['identifier, allowed_group']
|
71
70
|
```
|
72
|
-
|
71
|
+
|
72
|
+
If you wish to rerun a task, add an exclamation mark at the end of the identifier:
|
73
73
|
```bash
|
74
|
-
rake deploy_pin:run['
|
74
|
+
rake deploy_pin:run['identifier_1!, identifier_2!']
|
75
75
|
```
|
76
76
|
|
77
77
|
## Installation
|
78
78
|
|
79
|
-
|
80
79
|
Add this line to your application's Gemfile:
|
81
80
|
|
82
81
|
```ruby
|
83
82
|
gem 'deploy_pin'
|
84
83
|
```
|
85
84
|
|
86
|
-
|
85
|
+
Then execute:
|
87
86
|
```bash
|
88
87
|
$ bundle
|
89
88
|
```
|
90
89
|
|
91
|
-
|
90
|
+
You can also install it manually with:
|
92
91
|
```bash
|
93
92
|
$ gem install deploy_pin
|
94
93
|
```
|
95
94
|
|
96
|
-
|
95
|
+
Afterward, generate the configuration file:
|
97
96
|
```bash
|
98
97
|
rails g deploy_pin:install
|
99
98
|
```
|
100
99
|
|
101
|
-
|
100
|
+
Finally, run the migration:
|
102
101
|
```bash
|
103
102
|
rake db:migrate
|
104
103
|
```
|
105
104
|
|
106
105
|
## Database Timeout
|
107
|
-
|
108
|
-
|
106
|
+
|
107
|
+
By default, deploy_pin runs all non-parallel tasks under a database statement timeout. To set a default value, you should define it in the deploy_pin initializer, for example:
|
108
|
+
|
109
109
|
```ruby
|
110
110
|
# config/initializers/deploy_pin.rb
|
111
111
|
DeployPin.setup do
|
112
|
-
statement_timeout 0.2.
|
112
|
+
statement_timeout 0.2.seconds # 200 ms
|
113
113
|
end
|
114
114
|
```
|
115
115
|
|
116
|
-
|
116
|
+
If you want to use a different value than the default, you need to specify it explicitly in the task, as shown below:
|
117
|
+
|
117
118
|
```ruby
|
118
|
-
# Some deploy_pin task
|
119
|
+
# Some deploy_pin task
|
119
120
|
# 20190401135040:I
|
120
121
|
# task_title: Execute some query with timeout
|
122
|
+
# affected_areas: none
|
121
123
|
|
122
124
|
# === task code goes down here ===
|
123
125
|
DeployPin::Database::execute_with_timeout do
|
@@ -125,28 +127,26 @@ DeployPin::Database::execute_with_timeout do
|
|
125
127
|
end
|
126
128
|
```
|
127
129
|
|
128
|
-
|
130
|
+
For more information about the parameters, please refer to the documentation [here](lib/deploy_pin/database.rb).
|
129
131
|
|
130
132
|
## Parallel
|
131
|
-
To run parallel tasks using timeout, it's required to use the parallel wrapper, which mimics parallel interface,
|
132
|
-
but adding the timeout option.
|
133
133
|
|
134
|
-
In a deploy_pin task, instead of using `Parallel.each(1..2, in_processes: 2)`, use:
|
134
|
+
To run parallel tasks using a timeout, you need to use the parallel wrapper, which mimics the parallel interface but adds the timeout option. In a deploy_pin task, instead of using `Parallel.each(1..2, in_processes: 2)`, use:
|
135
|
+
|
135
136
|
```ruby
|
136
137
|
parallel_each(1..2, in_processes: 2, timeout: 0.3.seconds) do |i|
|
137
|
-
# ActiveRecord::Base.connection_pool.with_connection
|
138
|
+
# ActiveRecord::Base.connection_pool.with_connection is already included in the parallel wrapper.
|
138
139
|
puts "Item: #{i}, Worker: #{Parallel.worker_number}"
|
139
140
|
ActiveRecord::Base.connection.execute("<some db query>")
|
140
141
|
end
|
141
142
|
```
|
142
143
|
|
143
|
-
Check the documentation [here](lib/deploy_pin/parallel_wrapper.rb).
|
144
|
+
Check the documentation [here](lib/deploy_pin/parallel_wrapper.rb) for more details.
|
144
145
|
|
145
146
|
## Formatting
|
146
|
-
`run_formatter` is used to format the output of a `run` task
|
147
|
-
`list_formatter` is used to format the output of a `list` task
|
148
147
|
|
149
|
-
|
148
|
+
`run_formatter` is used to format the output of a `run` task, and `list_formatter` is used to format the output of a `list` task. To set a default value, you should define it in the deploy_pin initializer:
|
149
|
+
|
150
150
|
```ruby
|
151
151
|
# config/initializers/deploy_pin.rb
|
152
152
|
DeployPin.setup do
|
@@ -158,14 +158,14 @@ DeployPin.setup do
|
|
158
158
|
"(Skipped)\n\n"
|
159
159
|
end
|
160
160
|
|
161
|
-
puts("[#{index + 1}/#{task_count}] Task #{task.title} #{task.
|
161
|
+
puts("[#{index + 1}/#{task_count}] Task #{task.title} #{task.identifier}##{task.group} #{end_of_msg}".blue.bold)
|
162
162
|
end
|
163
163
|
)
|
164
164
|
list_formatter(
|
165
165
|
lambda do |index, task|
|
166
166
|
puts("======= Task ##{index} ========".blue.bold)
|
167
167
|
|
168
|
-
#
|
168
|
+
# Print details
|
169
169
|
task.details.each do |key, value|
|
170
170
|
puts("#{key}:\t\t#{value}")
|
171
171
|
end
|
@@ -176,16 +176,42 @@ DeployPin.setup do
|
|
176
176
|
end
|
177
177
|
```
|
178
178
|
|
179
|
-
|
179
|
+
To use a different formatting value than the default, you need to specify it explicitly in the task, similar to the database timeout configuration.
|
180
|
+
|
181
|
+
## Recurring Tasks
|
182
|
+
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.
|
183
|
+
|
184
|
+
Please note that two identifiers, 0 and -10, are already reserved for deployment state tracking. Avoid using these identifiers.
|
185
|
+
|
186
|
+
```bash
|
187
|
+
rails g deploy_pin:task some_task_title --recurring --identifier 5
|
188
|
+
# or
|
189
|
+
rails g deploy_pin:task some_task_title --parallel --recurring --identifier 5
|
190
|
+
```
|
191
|
+
|
192
|
+
## DeploymentStateTrack
|
193
|
+
In the initializer
|
180
194
|
```ruby
|
181
|
-
|
182
|
-
|
183
|
-
|
195
|
+
DeployPin.setup do
|
196
|
+
groups %w[I II III post rollback]
|
197
|
+
...
|
198
|
+
deployment_state_transition({
|
199
|
+
ongoing: %w[I III],
|
200
|
+
pending: "rollback", # enters to pending step before "rollback"
|
201
|
+
ttl: 20.second, # memoize the state to avoid Redis spam
|
202
|
+
redis_url: "redis://localhost:6379"
|
203
|
+
})
|
204
|
+
end
|
184
205
|
|
185
|
-
#
|
186
|
-
DeployPin
|
187
|
-
|
188
|
-
|
206
|
+
# enabled next methods
|
207
|
+
DeployPin.ongoing_deployment?
|
208
|
+
DeployPin.pending_deployment?
|
209
|
+
```
|
210
|
+
|
211
|
+
Around the deployment
|
212
|
+
```bash
|
213
|
+
bundle exec rake deploy_pin:run[I, II, III] - # enters to ongoing state before "I" and leaves it after "III" so all tasks in I, II, III have DeployPin.oingoing_deployment? == true
|
214
|
+
bundle exec rake deploy_pin:run[rollback] - # enters "pending state"
|
189
215
|
```
|
190
216
|
|
191
217
|
## Contributing
|
data/lib/deploy_pin/collector.rb
CHANGED
@@ -66,9 +66,9 @@ module DeployPin
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def tasks
|
69
|
-
files.map do |file|
|
69
|
+
[*DeployPin.deployment_tasks_code, *files].map do |file|
|
70
70
|
task = DeployPin::Task.new(file)
|
71
|
-
task.
|
71
|
+
task.parse
|
72
72
|
|
73
73
|
# check if task is suitable
|
74
74
|
task if task_criteria.suitable?(task)
|
data/lib/deploy_pin/database.rb
CHANGED
@@ -21,6 +21,7 @@ module DeployPin
|
|
21
21
|
# # <app root>/deploy_pin/20190401135040_task.rb
|
22
22
|
# # 20190401135040:I
|
23
23
|
# # task_title: Execute some query with timeout
|
24
|
+
# # affected_areas: none
|
24
25
|
#
|
25
26
|
# # === task code goes down here ===
|
26
27
|
# DeployPin::Database::execute_with_timeout do
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'connection_pool'
|
4
|
+
require 'redis'
|
5
|
+
|
6
|
+
# This module is used to track the state of a deployment.
|
7
|
+
module DeployPin
|
8
|
+
# The mixin that extends DeployPin module with
|
9
|
+
# @ongoing_deployment? & @pending_deployment? methods
|
10
|
+
module DeploymentState
|
11
|
+
STORE_KEY = 'deploy_pin:deployment'
|
12
|
+
ONGOING = 'ongoing'
|
13
|
+
PENDING = 'pending'
|
14
|
+
|
15
|
+
DEPLOYMENT_OVER_TASK = %(
|
16
|
+
# no_file_task
|
17
|
+
# -10:%<group>s:recurring
|
18
|
+
# task_title: Cleanup DeployPin.state
|
19
|
+
|
20
|
+
DeployPin.send(:deployment_over!)
|
21
|
+
).strip
|
22
|
+
|
23
|
+
DEPLOYMENT_ONGOING_TASK = %(
|
24
|
+
# no_file_task
|
25
|
+
# 0:%<group>s:recurring
|
26
|
+
# task_title: Set DeployPin.state to 'ongoing'
|
27
|
+
|
28
|
+
DeployPin.send(:deployment_ongoing!)
|
29
|
+
).strip
|
30
|
+
|
31
|
+
DEPLOYMENT_PENDING_TASK = %(
|
32
|
+
# no_file_task
|
33
|
+
# 0:%<group>s:recurring
|
34
|
+
# task_title: Set DeployPin.state to 'pending'
|
35
|
+
|
36
|
+
DeployPin.send(:deployment_pending!)
|
37
|
+
).strip
|
38
|
+
|
39
|
+
def ongoing_deployment?
|
40
|
+
deployment_state == ONGOING
|
41
|
+
end
|
42
|
+
|
43
|
+
def pending_deployment?
|
44
|
+
deployment_state == PENDING
|
45
|
+
end
|
46
|
+
|
47
|
+
def deployment_tasks_code
|
48
|
+
return [] unless DeployPin.enabled?(:deployment_state_transition)
|
49
|
+
|
50
|
+
ongoing_start_group, ongoing_end_group = DeployPin.deployment_state_transition[:ongoing]
|
51
|
+
rollback_group = DeployPin.deployment_state_transition[:pending]
|
52
|
+
|
53
|
+
[
|
54
|
+
format(DEPLOYMENT_ONGOING_TASK, group: ongoing_start_group),
|
55
|
+
format(DEPLOYMENT_OVER_TASK, group: ongoing_end_group),
|
56
|
+
format(DEPLOYMENT_PENDING_TASK, group: rollback_group)
|
57
|
+
]
|
58
|
+
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
def deployment_over!
|
63
|
+
in_memory_store.delete(:deployment)
|
64
|
+
persistent_store.del(STORE_KEY)
|
65
|
+
end
|
66
|
+
|
67
|
+
def deployment_ongoing!
|
68
|
+
persistent_store.set(STORE_KEY, ONGOING)
|
69
|
+
end
|
70
|
+
|
71
|
+
def deployment_pending!
|
72
|
+
persistent_store.set(STORE_KEY, PENDING)
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def in_memory_store
|
78
|
+
Thread.current[:deploy_pin] ||= {}
|
79
|
+
end
|
80
|
+
|
81
|
+
def persistent_store
|
82
|
+
@persistent_store ||= ConnectionPool::Wrapper.new do
|
83
|
+
Redis.new(url: DeployPin.deployment_state_transition[:redis_url])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def deployment_state
|
88
|
+
state = in_memory_store[:deployment] || {}
|
89
|
+
|
90
|
+
if state.blank? || state[:expiration] < Time.current
|
91
|
+
in_memory_store[:deployment] = {
|
92
|
+
expiration: DeployPin.deployment_state_transition[:ttl].from_now,
|
93
|
+
state: persistent_store.get(STORE_KEY)
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
in_memory_store[:deployment][:state]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
extend DeploymentState
|
102
|
+
end
|
data/lib/deploy_pin/task.rb
CHANGED
@@ -7,15 +7,16 @@ module DeployPin
|
|
7
7
|
include ::DeployPin::ParallelWrapper
|
8
8
|
|
9
9
|
attr_reader :file,
|
10
|
-
:
|
10
|
+
:identifier,
|
11
11
|
:group,
|
12
12
|
:title,
|
13
13
|
:script,
|
14
|
+
:recurring,
|
14
15
|
:explicit_timeout
|
15
16
|
|
16
17
|
def initialize(file)
|
17
18
|
@file = file
|
18
|
-
@
|
19
|
+
@identifier = nil
|
19
20
|
@group = nil
|
20
21
|
@title = ''
|
21
22
|
@script = ''
|
@@ -29,24 +30,29 @@ module DeployPin
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def mark
|
33
|
+
return if recurring
|
34
|
+
|
32
35
|
# store record in the DB
|
33
|
-
DeployPin::Record.create(uuid:
|
36
|
+
DeployPin::Record.create(uuid: identifier)
|
34
37
|
end
|
35
38
|
|
36
39
|
def done?
|
37
|
-
|
40
|
+
return if recurring
|
41
|
+
|
42
|
+
DeployPin::Record.where(uuid: identifier).exists?
|
38
43
|
end
|
39
44
|
|
40
45
|
def under_timeout?
|
41
46
|
!explicit_timeout? && !parallel?
|
42
47
|
end
|
43
48
|
|
44
|
-
def
|
45
|
-
|
49
|
+
def parse
|
50
|
+
each_line do |line|
|
46
51
|
case line.strip
|
47
|
-
when /\A# (
|
48
|
-
@
|
52
|
+
when /\A# (-?\d+):(\w+):?(recurring)?/
|
53
|
+
@identifier = Regexp.last_match(1).to_i
|
49
54
|
@group = Regexp.last_match(2)
|
55
|
+
@recurring = Regexp.last_match(3)
|
50
56
|
when /\A# task_title:(.+)/
|
51
57
|
@title = Regexp.last_match(1).strip
|
52
58
|
when /\A[^#].*/
|
@@ -58,25 +64,46 @@ module DeployPin
|
|
58
64
|
end
|
59
65
|
end
|
60
66
|
|
67
|
+
def each_line(&block)
|
68
|
+
if file.starts_with?('# no_file_task')
|
69
|
+
file.each_line(&block)
|
70
|
+
else
|
71
|
+
File.foreach(file, &block)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
61
75
|
def details
|
62
76
|
{
|
63
|
-
|
77
|
+
identifier: identifier,
|
64
78
|
group: group,
|
65
79
|
title: title
|
66
80
|
}
|
67
81
|
end
|
68
82
|
|
69
83
|
def eql?(other)
|
70
|
-
# same script & different
|
71
|
-
script == other.script &&
|
84
|
+
# same script & different identifier
|
85
|
+
script == other.script && identifier != other.identifier
|
72
86
|
end
|
73
87
|
|
74
|
-
|
88
|
+
def unreachable_future
|
89
|
+
1.year.from_now.to_date.strftime('%Y%m%d%H%M%S').to_i
|
90
|
+
end
|
75
91
|
|
76
|
-
|
77
|
-
|
78
|
-
group_index
|
92
|
+
def sorting_key
|
93
|
+
if identifier.to_i.negative?
|
94
|
+
[group_index, unreachable_future + identifier]
|
95
|
+
else
|
96
|
+
[group_index, identifier]
|
79
97
|
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# for sorting
|
101
|
+
def <=>(other)
|
102
|
+
sorting_key <=> other.sorting_key
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
|
80
107
|
|
81
108
|
def group_index
|
82
109
|
DeployPin.groups.index(group)
|
@@ -3,9 +3,9 @@
|
|
3
3
|
# check task criteria
|
4
4
|
module DeployPin
|
5
5
|
class TaskCriteria
|
6
|
-
SKIP_REGEXEP = /\A
|
7
|
-
FORCE_REGEXP = /\A([
|
8
|
-
COMMON_REGEXP = /(^[
|
6
|
+
SKIP_REGEXEP = /\A!(.+[^!])\z/
|
7
|
+
FORCE_REGEXP = /\A([^!].+)!\z/
|
8
|
+
COMMON_REGEXP = /(^[^!]?.+[^!]?$)/
|
9
9
|
|
10
10
|
attr_reader :identifiers
|
11
11
|
|
@@ -17,7 +17,7 @@ module DeployPin
|
|
17
17
|
task_cover = lambda { |task, regexp|
|
18
18
|
items = identifiers.flat_map { |x| x.to_s.scan(regexp) }.flatten
|
19
19
|
|
20
|
-
items & [task.group, task.
|
20
|
+
items & [task.group, task.identifier.to_s]
|
21
21
|
}
|
22
22
|
|
23
23
|
return false if task_cover.call(task, SKIP_REGEXEP).any?
|
data/lib/deploy_pin/version.rb
CHANGED
data/lib/deploy_pin.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'deploy_pin/deployment_state'
|
3
4
|
require 'deploy_pin/runner'
|
4
5
|
require 'deploy_pin/collector'
|
5
6
|
require 'deploy_pin/parallel_wrapper'
|
@@ -20,8 +21,13 @@ module DeployPin
|
|
20
21
|
run_formatter
|
21
22
|
list_formatter
|
22
23
|
task_wrapper
|
24
|
+
deployment_state_transition
|
23
25
|
].freeze
|
24
26
|
|
27
|
+
DEFAULTS = {
|
28
|
+
task_wrapper: ->(_task, task_runner) { task_runner.call }
|
29
|
+
}.freeze
|
30
|
+
|
25
31
|
OPTIONS.each do |option|
|
26
32
|
instance_eval %{
|
27
33
|
def #{option}(val = nil)
|
@@ -37,8 +43,14 @@ module DeployPin
|
|
37
43
|
end
|
38
44
|
|
39
45
|
def self.setup_defaults!
|
40
|
-
|
46
|
+
DEFAULTS.each do |option, value|
|
47
|
+
instance_variable_set(:"@#{option}", value)
|
48
|
+
end
|
41
49
|
end
|
42
50
|
|
43
51
|
setup_defaults!
|
52
|
+
|
53
|
+
def self.enabled?(option)
|
54
|
+
instance_variable_defined?("@#{option}")
|
55
|
+
end
|
44
56
|
end
|
@@ -2,9 +2,15 @@
|
|
2
2
|
|
3
3
|
DeployPin.setup do
|
4
4
|
tasks_path 'lib/deploy_pin'
|
5
|
-
groups %w[I II III]
|
6
|
-
fallback_group '
|
5
|
+
groups %w[pre I II III]
|
6
|
+
fallback_group 'III'
|
7
7
|
statement_timeout 10.minutes
|
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
|
+
})
|
8
14
|
run_formatter(
|
9
15
|
lambda do |index, task_count, task, executable, start, duration = nil|
|
10
16
|
end_of_msg = if executable
|
@@ -13,7 +19,7 @@ DeployPin.setup do
|
|
13
19
|
"(Skipped)\n\n"
|
14
20
|
end
|
15
21
|
|
16
|
-
puts("[#{index + 1}/#{task_count}] Task #{task.title} #{task.
|
22
|
+
puts("[#{index + 1}/#{task_count}] Task #{task.title} #{task.identifier}##{task.group} #{end_of_msg}".blue.bold)
|
17
23
|
end
|
18
24
|
)
|
19
25
|
list_formatter(
|
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
module DeployPin
|
4
4
|
class TaskGenerator < Rails::Generators::Base
|
5
|
-
class_option :parallel, type: :boolean
|
5
|
+
class_option :parallel, type: :boolean, aliases: '-p'
|
6
|
+
class_option :recurring, type: :boolean, aliases: '-r'
|
7
|
+
class_option :identifier, aliases: '-i'
|
6
8
|
argument :title, required: true
|
7
9
|
class_option :group, aliases: '-g', default: DeployPin.fallback_group
|
8
10
|
class_option :author, aliases: '-a'
|
@@ -19,8 +21,10 @@ module DeployPin
|
|
19
21
|
|
20
22
|
@author = options[:author] || ENV['USER']
|
21
23
|
@group = options[:group]
|
22
|
-
@
|
23
|
-
|
24
|
+
@recurring = options[:recurring]
|
25
|
+
@identifier = @recurring ? options[:identifier] : Time.now.strftime('%Y%m%d%H%M%S')
|
26
|
+
filename = @recurring ? "r_#{@identifier}_#{title}.rb" : "#{@identifier}_#{title}.rb"
|
27
|
+
template template_file, "#{DeployPin.tasks_path}/#{filename}"
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# <%= @
|
3
|
+
# <%= @identifier %>:<%= @group %><%= @recurring ? ":recurring" : "" %>
|
4
4
|
# task_title: <%= @author ? "@#{@author} #{title.titleize}" : "#{title.titleize}" %>
|
5
|
+
# affected_areas: none
|
5
6
|
|
6
7
|
# === parallel task code goes down here ===
|
7
8
|
10.times { DeployPin::Record.create(uuid: "hello") }
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# <%= @
|
3
|
+
# <%= @identifier %>:<%= @group %><%= @recurring ? ":recurring" : "" %>
|
4
4
|
# task_title: <%= @author ? "@#{@author} #{title.titleize}" : "#{title.titleize}" %>
|
5
|
+
# affected_areas: none
|
5
6
|
|
6
7
|
# === task code goes down here ===
|
7
8
|
progressbar = ProgressBar.create(title: "Doing stuff", total: 20, format: '%t |%E | %B | %a')
|
metadata
CHANGED
@@ -1,71 +1,99 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deploy_pin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Viktor Sych
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '1.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '1.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: connection_pool
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.2'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: parallel
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
47
|
+
version: '1.23'
|
34
48
|
type: :runtime
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
54
|
+
version: '1.23'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rails
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- - "
|
59
|
+
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
61
|
+
version: '7.0'
|
48
62
|
type: :runtime
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
|
-
- - "
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '7.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: redis
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">"
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
82
|
+
version: '4.0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: ruby-progressbar
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
58
86
|
requirements:
|
59
87
|
- - "~>"
|
60
88
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1.
|
89
|
+
version: '1.13'
|
62
90
|
type: :runtime
|
63
91
|
prerelease: false
|
64
92
|
version_requirements: !ruby/object:Gem::Requirement
|
65
93
|
requirements:
|
66
94
|
- - "~>"
|
67
95
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1.
|
96
|
+
version: '1.13'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: bundler
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -207,6 +235,7 @@ files:
|
|
207
235
|
- lib/deploy_pin.rb
|
208
236
|
- lib/deploy_pin/collector.rb
|
209
237
|
- lib/deploy_pin/database.rb
|
238
|
+
- lib/deploy_pin/deployment_state.rb
|
210
239
|
- lib/deploy_pin/engine.rb
|
211
240
|
- lib/deploy_pin/parallel_wrapper.rb
|
212
241
|
- lib/deploy_pin/runner.rb
|
@@ -227,7 +256,7 @@ licenses:
|
|
227
256
|
- MIT
|
228
257
|
metadata:
|
229
258
|
allowed_push_host: https://rubygems.org
|
230
|
-
post_install_message:
|
259
|
+
post_install_message:
|
231
260
|
rdoc_options: []
|
232
261
|
require_paths:
|
233
262
|
- lib
|
@@ -235,15 +264,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
235
264
|
requirements:
|
236
265
|
- - ">="
|
237
266
|
- !ruby/object:Gem::Version
|
238
|
-
version: '
|
267
|
+
version: '3.0'
|
239
268
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
240
269
|
requirements:
|
241
270
|
- - ">="
|
242
271
|
- !ruby/object:Gem::Version
|
243
272
|
version: '0'
|
244
273
|
requirements: []
|
245
|
-
rubygems_version: 3.
|
246
|
-
signing_key:
|
274
|
+
rubygems_version: 3.5.11
|
275
|
+
signing_key:
|
247
276
|
specification_version: 4
|
248
277
|
summary: pin some task around deployment
|
249
278
|
test_files: []
|