rails-worktrees 0.3.0 → 0.5.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 +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +19 -9
- data/README.md +55 -3
- data/lib/generators/rails/worktrees/templates/rails_worktrees.rb.tt +19 -15
- data/lib/rails/worktrees/command/git_operations.rb +65 -4
- data/lib/rails/worktrees/command/output.rb +90 -3
- data/lib/rails/worktrees/command/workspace_paths.rb +34 -0
- data/lib/rails/worktrees/command.rb +429 -18
- data/lib/rails/worktrees/initializer_updater.rb +148 -0
- data/lib/rails/worktrees/project_maintenance.rb +326 -0
- data/lib/rails/worktrees/version.rb +1 -1
- data/lib/rails/worktrees.rb +2 -0
- metadata +3 -1
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Worktrees
|
|
3
|
+
# Audits and prepares safe file-based maintenance updates for the current checkout.
|
|
4
|
+
# rubocop:disable Metrics/ClassLength, Metrics/MethodLength, Metrics/AbcSize
|
|
5
|
+
class ProjectMaintenance
|
|
6
|
+
# rubocop:disable Style/RedundantStructKeywordInit
|
|
7
|
+
Check = Struct.new(
|
|
8
|
+
:identifier,
|
|
9
|
+
:category,
|
|
10
|
+
:headline,
|
|
11
|
+
:messages,
|
|
12
|
+
:relative_path,
|
|
13
|
+
:status,
|
|
14
|
+
:updated_content,
|
|
15
|
+
:make_executable,
|
|
16
|
+
:apply_messages,
|
|
17
|
+
keyword_init: true
|
|
18
|
+
) do
|
|
19
|
+
def ok?
|
|
20
|
+
status == :ok
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def fixable?
|
|
24
|
+
status == :fixable
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def warning?
|
|
28
|
+
status == :warning
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def updatable?
|
|
32
|
+
!updated_content.nil?
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Report = Struct.new(:checks, keyword_init: true) do
|
|
37
|
+
def fixable_checks
|
|
38
|
+
checks.select(&:fixable?)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def warning_checks
|
|
42
|
+
checks.select(&:warning?)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def ok?
|
|
46
|
+
fixable_checks.empty? && warning_checks.empty?
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
# rubocop:enable Style/RedundantStructKeywordInit
|
|
50
|
+
|
|
51
|
+
TEMPLATE_ROOT = File.expand_path('../../generators/rails/worktrees/templates', __dir__)
|
|
52
|
+
|
|
53
|
+
def initialize(root:)
|
|
54
|
+
@root = root
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def call
|
|
58
|
+
Report.new(checks: maintenance_checks.compact)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
attr_reader :root
|
|
64
|
+
|
|
65
|
+
def maintenance_checks
|
|
66
|
+
[
|
|
67
|
+
template_file_check(wrapper_config),
|
|
68
|
+
initializer_check,
|
|
69
|
+
database_check,
|
|
70
|
+
optional_updater_check(procfile_config) { |content| ProcfileUpdater.new(content: content).call },
|
|
71
|
+
optional_updater_check(puma_config) { |content| PumaConfigUpdater.new(content: content).call },
|
|
72
|
+
mise_check,
|
|
73
|
+
template_file_check(browser_wrapper_config)
|
|
74
|
+
]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def wrapper_config
|
|
78
|
+
{
|
|
79
|
+
identifier: :bin_wt,
|
|
80
|
+
category: :install,
|
|
81
|
+
relative_path: 'bin/wt',
|
|
82
|
+
template_path: File.join(TEMPLATE_ROOT, 'bin/wt'),
|
|
83
|
+
make_executable: true,
|
|
84
|
+
optional: false
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def browser_wrapper_config
|
|
89
|
+
{
|
|
90
|
+
identifier: :bin_ob,
|
|
91
|
+
category: :install,
|
|
92
|
+
relative_path: 'bin/ob',
|
|
93
|
+
template_path: File.join(TEMPLATE_ROOT, 'bin/ob'),
|
|
94
|
+
make_executable: true,
|
|
95
|
+
optional: true
|
|
96
|
+
}
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def template_file_check(config)
|
|
100
|
+
path = absolute_path(config.fetch(:relative_path))
|
|
101
|
+
return nil if config.fetch(:optional) && !File.exist?(path)
|
|
102
|
+
|
|
103
|
+
desired_content = File.read(config.fetch(:template_path))
|
|
104
|
+
return template_missing_check(config, desired_content) unless File.exist?(path)
|
|
105
|
+
|
|
106
|
+
current_content = File.read(path)
|
|
107
|
+
if current_content == desired_content
|
|
108
|
+
if executable_mode_current?(config, path)
|
|
109
|
+
return ok_check(config, "#{config.fetch(:relative_path)} is up to date.")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
return executable_permission_check(config, desired_content)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
fixable_check(
|
|
116
|
+
config,
|
|
117
|
+
"#{config.fetch(:relative_path)} differs from the managed template.",
|
|
118
|
+
updated_content: desired_content,
|
|
119
|
+
apply_messages: ["Updated #{config.fetch(:relative_path)} to match the managed template."],
|
|
120
|
+
make_executable: config.fetch(:make_executable, false)
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def executable_mode_current?(config, path)
|
|
125
|
+
!config.fetch(:make_executable, false) || File.executable?(path)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def executable_permission_check(config, desired_content)
|
|
129
|
+
relative_path = config.fetch(:relative_path)
|
|
130
|
+
fixable_check(
|
|
131
|
+
config,
|
|
132
|
+
"#{relative_path} needs its executable bit restored.",
|
|
133
|
+
updated_content: desired_content,
|
|
134
|
+
apply_messages: ["Restored executable permissions on #{relative_path}."],
|
|
135
|
+
make_executable: true
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def template_missing_check(config, desired_content)
|
|
140
|
+
fixable_check(
|
|
141
|
+
config,
|
|
142
|
+
"#{config.fetch(:relative_path)} is missing.",
|
|
143
|
+
updated_content: desired_content,
|
|
144
|
+
apply_messages: ["Created #{config.fetch(:relative_path)} from the managed template."],
|
|
145
|
+
make_executable: config.fetch(:make_executable, false)
|
|
146
|
+
)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def initializer_check
|
|
150
|
+
config = {
|
|
151
|
+
identifier: :initializer,
|
|
152
|
+
category: :install,
|
|
153
|
+
relative_path: 'config/initializers/rails_worktrees.rb',
|
|
154
|
+
identical_headline: 'config/initializers/rails_worktrees.rb already uses the current safety guard.',
|
|
155
|
+
fixable_headline: 'config/initializers/rails_worktrees.rb can be updated automatically.',
|
|
156
|
+
warning_headline: 'config/initializers/rails_worktrees.rb needs manual review.'
|
|
157
|
+
}
|
|
158
|
+
path = absolute_path(config.fetch(:relative_path))
|
|
159
|
+
|
|
160
|
+
unless File.exist?(path)
|
|
161
|
+
return fixable_check(
|
|
162
|
+
config,
|
|
163
|
+
"#{config.fetch(:relative_path)} is missing.",
|
|
164
|
+
updated_content: InitializerUpdater.default_content,
|
|
165
|
+
apply_messages: ['Created config/initializers/rails_worktrees.rb with the current safety guard.']
|
|
166
|
+
)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
updater_result_check(config, InitializerUpdater.new(content: File.read(path)).call)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def database_check
|
|
173
|
+
config = {
|
|
174
|
+
identifier: :database,
|
|
175
|
+
category: :config,
|
|
176
|
+
relative_path: 'config/database.yml'
|
|
177
|
+
}
|
|
178
|
+
path = absolute_path(config.fetch(:relative_path))
|
|
179
|
+
|
|
180
|
+
unless File.exist?(path)
|
|
181
|
+
return warning_check(
|
|
182
|
+
config,
|
|
183
|
+
'config/database.yml is missing.',
|
|
184
|
+
['Add WORKTREE_DATABASE_SUFFIX support manually if this app uses a custom database setup.']
|
|
185
|
+
)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
result = DatabaseConfigUpdater.new(content: File.read(path)).call
|
|
189
|
+
return updated_database_check(config, result) if result.changed?
|
|
190
|
+
|
|
191
|
+
if database_configured?(result)
|
|
192
|
+
return ok_check(
|
|
193
|
+
config,
|
|
194
|
+
'config/database.yml already includes WORKTREE_DATABASE_SUFFIX in supported entries.'
|
|
195
|
+
)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
warning_check(
|
|
199
|
+
config,
|
|
200
|
+
result.messages.first || 'config/database.yml needs manual review.',
|
|
201
|
+
result.messages.drop(1)
|
|
202
|
+
)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def updated_database_check(config, result)
|
|
206
|
+
fixable_check(
|
|
207
|
+
config,
|
|
208
|
+
'config/database.yml can be updated automatically.',
|
|
209
|
+
messages: result.messages.drop(1),
|
|
210
|
+
updated_content: result.content,
|
|
211
|
+
apply_messages: result.messages
|
|
212
|
+
)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def database_configured?(result)
|
|
216
|
+
result.messages.first == 'Development/test database names already include WORKTREE_DATABASE_SUFFIX.'
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def procfile_config
|
|
220
|
+
{
|
|
221
|
+
identifier: :procfile,
|
|
222
|
+
category: :config,
|
|
223
|
+
relative_path: 'Procfile.dev',
|
|
224
|
+
identical_headline: 'Procfile.dev already uses the DEV_PORT-aware web entry.',
|
|
225
|
+
fixable_headline: 'Procfile.dev can be updated automatically.',
|
|
226
|
+
warning_headline: 'Procfile.dev needs manual review.'
|
|
227
|
+
}
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def puma_config
|
|
231
|
+
{
|
|
232
|
+
identifier: :puma,
|
|
233
|
+
category: :config,
|
|
234
|
+
relative_path: 'config/puma.rb',
|
|
235
|
+
identical_headline: 'config/puma.rb already prefers DEV_PORT.',
|
|
236
|
+
fixable_headline: 'config/puma.rb can be updated automatically.',
|
|
237
|
+
warning_headline: 'config/puma.rb needs manual review.'
|
|
238
|
+
}
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def optional_updater_check(config)
|
|
242
|
+
path = absolute_path(config.fetch(:relative_path))
|
|
243
|
+
return unless File.exist?(path)
|
|
244
|
+
|
|
245
|
+
updater_result_check(config, yield(File.read(path)))
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def mise_check
|
|
249
|
+
relative_path = %w[mise.toml .mise.toml].find { |candidate| File.exist?(absolute_path(candidate)) }
|
|
250
|
+
return unless relative_path
|
|
251
|
+
|
|
252
|
+
config = {
|
|
253
|
+
identifier: :mise,
|
|
254
|
+
category: :config,
|
|
255
|
+
relative_path: relative_path,
|
|
256
|
+
identical_headline: "#{relative_path} already loads .env from [env].",
|
|
257
|
+
fixable_headline: "#{relative_path} can be updated automatically.",
|
|
258
|
+
warning_headline: "#{relative_path} needs manual review."
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
updater_result_check(config, mise_updater_result(relative_path))
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def mise_updater_result(relative_path)
|
|
265
|
+
MiseTomlUpdater.new(
|
|
266
|
+
content: File.read(absolute_path(relative_path)),
|
|
267
|
+
file_name: File.basename(relative_path)
|
|
268
|
+
).call
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def updater_result_check(config, result)
|
|
272
|
+
case result.status
|
|
273
|
+
when :identical
|
|
274
|
+
ok_check(config, config.fetch(:identical_headline))
|
|
275
|
+
when :updated
|
|
276
|
+
fixable_check(
|
|
277
|
+
config,
|
|
278
|
+
config.fetch(:fixable_headline),
|
|
279
|
+
updated_content: result.content,
|
|
280
|
+
apply_messages: result.messages
|
|
281
|
+
)
|
|
282
|
+
else
|
|
283
|
+
warning_check(config, config.fetch(:warning_headline), result.messages)
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def ok_check(config, headline)
|
|
288
|
+
build_check(config, status: :ok, headline: headline)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def warning_check(config, headline, messages = [])
|
|
292
|
+
build_check(config, status: :warning, headline: headline, messages: messages)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def fixable_check(config, headline, updated_content:, apply_messages:, **attributes)
|
|
296
|
+
build_check(
|
|
297
|
+
config,
|
|
298
|
+
status: :fixable,
|
|
299
|
+
headline: headline,
|
|
300
|
+
updated_content: updated_content,
|
|
301
|
+
apply_messages: apply_messages,
|
|
302
|
+
**attributes
|
|
303
|
+
)
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def build_check(config, status:, headline:, **attributes)
|
|
307
|
+
Check.new(
|
|
308
|
+
identifier: config.fetch(:identifier),
|
|
309
|
+
category: config.fetch(:category),
|
|
310
|
+
relative_path: config.fetch(:relative_path),
|
|
311
|
+
status: status,
|
|
312
|
+
headline: headline,
|
|
313
|
+
messages: attributes.fetch(:messages, []),
|
|
314
|
+
updated_content: attributes.fetch(:updated_content, nil),
|
|
315
|
+
make_executable: attributes.fetch(:make_executable, false),
|
|
316
|
+
apply_messages: attributes.fetch(:apply_messages, [])
|
|
317
|
+
)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def absolute_path(relative_path)
|
|
321
|
+
File.join(root, relative_path)
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
# rubocop:enable Metrics/ClassLength, Metrics/MethodLength, Metrics/AbcSize
|
|
325
|
+
end
|
|
326
|
+
end
|
data/lib/rails/worktrees.rb
CHANGED
|
@@ -7,9 +7,11 @@ require_relative 'worktrees/command'
|
|
|
7
7
|
require_relative 'worktrees/cli'
|
|
8
8
|
require_relative 'worktrees/browser_command'
|
|
9
9
|
require_relative 'worktrees/database_config_updater'
|
|
10
|
+
require_relative 'worktrees/initializer_updater'
|
|
10
11
|
require_relative 'worktrees/procfile_updater'
|
|
11
12
|
require_relative 'worktrees/mise_toml_updater'
|
|
12
13
|
require_relative 'worktrees/puma_config_updater'
|
|
14
|
+
require_relative 'worktrees/project_maintenance'
|
|
13
15
|
|
|
14
16
|
module Rails
|
|
15
17
|
# Rails-specific git worktree helpers and installer support.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-worktrees
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Asjer Querido
|
|
@@ -66,9 +66,11 @@ files:
|
|
|
66
66
|
- lib/rails/worktrees/configuration.rb
|
|
67
67
|
- lib/rails/worktrees/database_config_updater.rb
|
|
68
68
|
- lib/rails/worktrees/env_bootstrapper.rb
|
|
69
|
+
- lib/rails/worktrees/initializer_updater.rb
|
|
69
70
|
- lib/rails/worktrees/mise_toml_updater.rb
|
|
70
71
|
- lib/rails/worktrees/names/cities.txt
|
|
71
72
|
- lib/rails/worktrees/procfile_updater.rb
|
|
73
|
+
- lib/rails/worktrees/project_maintenance.rb
|
|
72
74
|
- lib/rails/worktrees/puma_config_updater.rb
|
|
73
75
|
- lib/rails/worktrees/railtie.rb
|
|
74
76
|
- lib/rails/worktrees/version.rb
|