rails-worktrees 0.5.1 → 0.6.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 +7 -0
- data/lib/generators/rails/worktrees/templates/rails_worktrees.rb.tt +11 -0
- data/lib/rails/worktrees/command/post_create_support.rb +33 -0
- data/lib/rails/worktrees/command.rb +16 -1
- data/lib/rails/worktrees/configuration.rb +32 -2
- data/lib/rails/worktrees/credential_key_linker.rb +93 -0
- data/lib/rails/worktrees/post_create_runner.rb +201 -0
- data/lib/rails/worktrees/version.rb +1 -1
- data/lib/rails/worktrees.rb +2 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de8cd30214f81e827aee0e2fabba426a1c0cfca6f172d03fb36fad408fc8bfe7
|
|
4
|
+
data.tar.gz: 604eb3468c743e91b3b5ad19f9943fa94d9fe891b45732de491ddc8219c4b943
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8f33f141355afb0dbc9ee06cdaab2e2f242c7d49b7ac72b6c2aa21202aabc8fb709cf79aa88a0b43f2357240b19b88dab37cc284f3fd4f712cc2b6c1057b743b
|
|
7
|
+
data.tar.gz: c9bc8caa8f38b496e2d7dd4bc0693251ec18606863b349cf949398e2cc131c448277869e04ac873e80f8b3dfff3f1fc59604e7ba2207fff21a97c255376524f3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{".":"0.
|
|
1
|
+
{".":"0.6.0"}
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0](https://github.com/asjer/rails-worktrees/compare/v0.5.1...v0.6.0) (2026-04-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **post-create:** bootstrap new worktrees after creation ([b429105](https://github.com/asjer/rails-worktrees/commit/b42910507d21c1d048d45cfdc4d7311a1ec8a96b))
|
|
9
|
+
|
|
3
10
|
## [0.5.1](https://github.com/asjer/rails-worktrees/compare/v0.5.0...v0.5.1) (2026-04-02)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -16,4 +16,15 @@ Rails.application.config.x.rails_worktrees.tap do |config|
|
|
|
16
16
|
# 'rails-worktrees',
|
|
17
17
|
# 'used-names.tsv'
|
|
18
18
|
# )
|
|
19
|
+
|
|
20
|
+
# Post-create setup steps (run automatically after a new worktree is created)
|
|
21
|
+
# config.post_create_command = nil # nil = built-in steps; false = skip all; 'script/worktree-setup' = custom command
|
|
22
|
+
# config.run_bundle_install = true
|
|
23
|
+
# config.run_yarn_install = true # auto-skipped when yarn.lock is absent
|
|
24
|
+
# config.run_db_prepare = true
|
|
25
|
+
# config.run_test_db_prepare = true
|
|
26
|
+
# config.run_test_assets_precompile = true
|
|
27
|
+
# config.link_credential_keys = true # link development.key from a sibling worktree (opt-out)
|
|
28
|
+
# config.link_test_credential_key = false
|
|
29
|
+
# config.link_production_credential_key = false
|
|
19
30
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Worktrees
|
|
3
|
+
class Command
|
|
4
|
+
# Delegates post-create setup steps to PostCreateRunner.
|
|
5
|
+
module PostCreateSupport
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def run_post_create_steps(context)
|
|
9
|
+
post_create_runner_for(context).call(dry_run: false)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def preview_post_create_steps(context)
|
|
13
|
+
post_create_runner_for(context).call(dry_run: true)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def post_create_runner_for(context)
|
|
17
|
+
PostCreateRunner.new(
|
|
18
|
+
target_dir: context[:target_dir],
|
|
19
|
+
peer_roots: peer_roots_excluding(context[:target_dir]),
|
|
20
|
+
configuration: @configuration,
|
|
21
|
+
io: { stdout: @stdout, stderr: @stderr }
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def peer_roots_excluding(target_dir)
|
|
26
|
+
worktree_entries
|
|
27
|
+
.map { |entry| entry[:path] }
|
|
28
|
+
.reject { |path| path == target_dir }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -3,6 +3,7 @@ require_relative 'command/environment_support'
|
|
|
3
3
|
require_relative 'command/git_operations'
|
|
4
4
|
require_relative 'command/name_picking'
|
|
5
5
|
require_relative 'command/output'
|
|
6
|
+
require_relative 'command/post_create_support'
|
|
6
7
|
require_relative 'command/workspace_paths'
|
|
7
8
|
|
|
8
9
|
module Rails
|
|
@@ -18,6 +19,7 @@ module Rails
|
|
|
18
19
|
include EnvironmentSupport
|
|
19
20
|
include NamePicking
|
|
20
21
|
include Output
|
|
22
|
+
include PostCreateSupport
|
|
21
23
|
include WorkspacePaths
|
|
22
24
|
|
|
23
25
|
def initialize(argv:, io:, env:, cwd:, configuration:)
|
|
@@ -284,7 +286,20 @@ module Rails
|
|
|
284
286
|
def finish(context)
|
|
285
287
|
settle_retired_name(context[:worktree_name], context[:project_name], dry_run: dry_run?)
|
|
286
288
|
bootstrap_result = bootstrap_worktree_environment(context)
|
|
287
|
-
|
|
289
|
+
|
|
290
|
+
return complete_dry_run_after_setup(context, bootstrap_result) if dry_run?
|
|
291
|
+
|
|
292
|
+
complete_created_worktree(context, bootstrap_result)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def complete_dry_run_after_setup(context, bootstrap_result)
|
|
296
|
+
preview_post_create_steps(context)
|
|
297
|
+
complete_dry_run(context, env_values: bootstrap_result&.values)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def complete_created_worktree(context, bootstrap_result)
|
|
301
|
+
result = run_post_create_steps(context)
|
|
302
|
+
return result unless result.zero?
|
|
288
303
|
|
|
289
304
|
success('Worktree ready')
|
|
290
305
|
print_context_summary(context, env_values: bootstrap_result&.values)
|
|
@@ -10,6 +10,15 @@ module Rails
|
|
|
10
10
|
name_sources_path
|
|
11
11
|
used_names_file
|
|
12
12
|
worktree_database_suffix_max_length
|
|
13
|
+
post_create_command
|
|
14
|
+
run_bundle_install
|
|
15
|
+
run_yarn_install
|
|
16
|
+
run_db_prepare
|
|
17
|
+
run_test_db_prepare
|
|
18
|
+
run_test_assets_precompile
|
|
19
|
+
link_credential_keys
|
|
20
|
+
link_test_credential_key
|
|
21
|
+
link_production_credential_key
|
|
13
22
|
].freeze
|
|
14
23
|
|
|
15
24
|
DEFAULT_BOOTSTRAP_ENV = true
|
|
@@ -25,9 +34,20 @@ module Rails
|
|
|
25
34
|
|
|
26
35
|
attr_accessor :bootstrap_env, :branch_prefix, :dev_port_range, :legacy_used_names_files,
|
|
27
36
|
:name_sources_path, :used_names_file, :workspace_root,
|
|
28
|
-
:worktree_database_suffix_max_length
|
|
37
|
+
:worktree_database_suffix_max_length,
|
|
38
|
+
:post_create_command,
|
|
39
|
+
:run_bundle_install, :run_yarn_install,
|
|
40
|
+
:run_db_prepare, :run_test_db_prepare, :run_test_assets_precompile,
|
|
41
|
+
:link_credential_keys, :link_test_credential_key, :link_production_credential_key
|
|
29
42
|
|
|
30
43
|
def initialize
|
|
44
|
+
assign_core_defaults
|
|
45
|
+
assign_post_create_defaults
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def assign_core_defaults
|
|
31
51
|
@bootstrap_env = DEFAULT_BOOTSTRAP_ENV
|
|
32
52
|
@workspace_root = nil
|
|
33
53
|
@branch_prefix = DEFAULT_BRANCH_PREFIX
|
|
@@ -38,7 +58,17 @@ module Rails
|
|
|
38
58
|
@legacy_used_names_files = default_legacy_used_names_files
|
|
39
59
|
end
|
|
40
60
|
|
|
41
|
-
|
|
61
|
+
def assign_post_create_defaults
|
|
62
|
+
@post_create_command = nil
|
|
63
|
+
@run_bundle_install = true
|
|
64
|
+
@run_yarn_install = true
|
|
65
|
+
@run_db_prepare = true
|
|
66
|
+
@run_test_db_prepare = true
|
|
67
|
+
@run_test_assets_precompile = true
|
|
68
|
+
@link_credential_keys = true
|
|
69
|
+
@link_test_credential_key = false
|
|
70
|
+
@link_production_credential_key = false
|
|
71
|
+
end
|
|
42
72
|
|
|
43
73
|
def default_legacy_used_names_files
|
|
44
74
|
state_home = ENV.fetch('XDG_STATE_HOME', File.join(Dir.home, '.local/state'))
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
|
|
3
|
+
module Rails
|
|
4
|
+
module Worktrees
|
|
5
|
+
# Links credential key files from a sibling worktree into the new worktree.
|
|
6
|
+
class CredentialKeyLinker
|
|
7
|
+
Result = Struct.new(:messages)
|
|
8
|
+
|
|
9
|
+
CREDENTIALS_DIR = 'config/credentials'.freeze
|
|
10
|
+
|
|
11
|
+
KEY_TYPES = [
|
|
12
|
+
{ name: 'development', config_attr: :link_credential_keys },
|
|
13
|
+
{ name: 'test', config_attr: :link_test_credential_key },
|
|
14
|
+
{ name: 'production', config_attr: :link_production_credential_key }
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
def initialize(target_dir:, peer_roots:, configuration:)
|
|
18
|
+
@target_dir = target_dir
|
|
19
|
+
@peer_roots = peer_roots
|
|
20
|
+
@configuration = configuration
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def call(dry_run: false)
|
|
24
|
+
messages = []
|
|
25
|
+
|
|
26
|
+
KEY_TYPES.each do |key_type|
|
|
27
|
+
next unless @configuration.public_send(key_type[:config_attr])
|
|
28
|
+
|
|
29
|
+
message = process_key(key_type[:name], dry_run: dry_run)
|
|
30
|
+
messages << message if message
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Result.new(messages)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def process_key(key_name, dry_run:)
|
|
39
|
+
destination = destination_path_for(key_name)
|
|
40
|
+
existing_message = existing_destination_message(destination, key_name)
|
|
41
|
+
return existing_message if existing_message
|
|
42
|
+
|
|
43
|
+
replace_existing_symlink = File.symlink?(destination)
|
|
44
|
+
return "#{key_name}.key already exists; leaving as-is" if File.exist?(destination)
|
|
45
|
+
|
|
46
|
+
source = find_source(key_name)
|
|
47
|
+
return "Could not find source for #{key_name}.key" unless source
|
|
48
|
+
|
|
49
|
+
link_key(destination, key_name, source, dry_run: dry_run, replace_existing_symlink: replace_existing_symlink)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def find_source(key_name)
|
|
53
|
+
@peer_roots.each do |peer_root|
|
|
54
|
+
candidate = File.join(peer_root, CREDENTIALS_DIR, "#{key_name}.key")
|
|
55
|
+
next if File.expand_path(peer_root) == File.expand_path(@target_dir)
|
|
56
|
+
|
|
57
|
+
return candidate if File.file?(candidate)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def destination_path_for(key_name)
|
|
64
|
+
File.join(@target_dir, CREDENTIALS_DIR, "#{key_name}.key")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def existing_destination_message(destination, key_name)
|
|
68
|
+
return unless File.symlink?(destination) && File.exist?(destination)
|
|
69
|
+
|
|
70
|
+
"#{key_name}.key already linked"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def link_key(destination, key_name, source, dry_run:, replace_existing_symlink: false)
|
|
74
|
+
return dry_run_link_message(key_name, source, replace_existing_symlink) if dry_run
|
|
75
|
+
|
|
76
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
77
|
+
FileUtils.rm_f(destination) if replace_existing_symlink
|
|
78
|
+
File.symlink(source, destination)
|
|
79
|
+
linked_key_message(key_name, source, replace_existing_symlink)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def dry_run_link_message(key_name, source, replace_existing_symlink)
|
|
83
|
+
verb = replace_existing_symlink ? 'Would relink' : 'Would link'
|
|
84
|
+
"#{verb} #{key_name}.key → #{source}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def linked_key_message(key_name, source, replace_existing_symlink)
|
|
88
|
+
verb = replace_existing_symlink ? 'Relinked' : 'Linked'
|
|
89
|
+
"#{verb} #{key_name}.key → #{source}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
require 'open3'
|
|
2
|
+
|
|
3
|
+
module Rails
|
|
4
|
+
module Worktrees
|
|
5
|
+
# Runs post-create setup steps in a newly created worktree.
|
|
6
|
+
# Steps run in order: credential linking, bundle install, yarn install,
|
|
7
|
+
# db:prepare (development), db:prepare (test), assets:precompile (test).
|
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
|
9
|
+
class PostCreateRunner
|
|
10
|
+
STEPS = [
|
|
11
|
+
{ id: :bundle, argv: %w[bundle install],
|
|
12
|
+
header: '📦 Installing gems...' },
|
|
13
|
+
{ id: :yarn, argv: %w[yarn install],
|
|
14
|
+
header: '🧶 Installing JS dependencies...' },
|
|
15
|
+
{ id: :db_prepare, argv: %w[bin/rails db:prepare],
|
|
16
|
+
header: '🗄️ Preparing development database...', env: { 'RAILS_ENV' => 'development' } },
|
|
17
|
+
{ id: :test_db_prepare, argv: %w[bin/rails db:prepare],
|
|
18
|
+
header: '🗄️ Preparing test database...', env: { 'RAILS_ENV' => 'test' } },
|
|
19
|
+
{ id: :test_assets_precompile, argv: %w[bin/rails assets:precompile],
|
|
20
|
+
header: '🎨 Precompiling test assets...', env: { 'RAILS_ENV' => 'test' } }
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
STEP_CONFIG = {
|
|
24
|
+
bundle: :run_bundle_install,
|
|
25
|
+
yarn: :run_yarn_install,
|
|
26
|
+
db_prepare: :run_db_prepare,
|
|
27
|
+
test_db_prepare: :run_test_db_prepare,
|
|
28
|
+
test_assets_precompile: :run_test_assets_precompile
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
def initialize(target_dir:, peer_roots:, configuration:, io:)
|
|
32
|
+
@target_dir = target_dir
|
|
33
|
+
@peer_roots = peer_roots
|
|
34
|
+
@configuration = configuration
|
|
35
|
+
@stdout = io.fetch(:stdout)
|
|
36
|
+
@stderr = io.fetch(:stderr)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def call(dry_run: false)
|
|
40
|
+
return 0 if @configuration.post_create_command == false
|
|
41
|
+
|
|
42
|
+
return run_custom_command(dry_run: dry_run) if custom_command?
|
|
43
|
+
|
|
44
|
+
run_built_in_steps(dry_run: dry_run)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def custom_command?
|
|
50
|
+
@configuration.post_create_command.is_a?(String) && !@configuration.post_create_command.empty?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def run_custom_command(dry_run:)
|
|
54
|
+
command = @configuration.post_create_command
|
|
55
|
+
|
|
56
|
+
if dry_run
|
|
57
|
+
info("Would run: #{command}")
|
|
58
|
+
return 0
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
info("Running: #{command}")
|
|
62
|
+
stream_shell_command(command)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def run_built_in_steps(dry_run:)
|
|
66
|
+
result = run_credential_linking(dry_run: dry_run)
|
|
67
|
+
return result unless result.zero?
|
|
68
|
+
|
|
69
|
+
STEPS.each do |step|
|
|
70
|
+
config_attr = STEP_CONFIG[step[:id]]
|
|
71
|
+
next unless @configuration.public_send(config_attr)
|
|
72
|
+
next if step[:id] == :yarn && !yarn_lock_present?
|
|
73
|
+
|
|
74
|
+
result = run_step(step, dry_run: dry_run)
|
|
75
|
+
return result unless result.zero?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
0
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def run_credential_linking(dry_run:)
|
|
82
|
+
# Missing peer key files are intentionally best-effort and should not abort
|
|
83
|
+
# worktree setup; the linker reports those cases in its messages while real
|
|
84
|
+
# filesystem errors still raise out of `credential_key_linker.call`.
|
|
85
|
+
return 0 unless credential_linking_enabled?
|
|
86
|
+
|
|
87
|
+
info('🔑 Linking credential keys...')
|
|
88
|
+
|
|
89
|
+
result = credential_key_linker.call(dry_run: dry_run)
|
|
90
|
+
print_credential_linking_messages(result)
|
|
91
|
+
|
|
92
|
+
0
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def run_step(step, dry_run:)
|
|
96
|
+
if dry_run
|
|
97
|
+
info("Would run: #{display_command(step)}")
|
|
98
|
+
return 0
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
info(step[:header])
|
|
102
|
+
stream_step_command(step)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def stream_shell_command(command)
|
|
106
|
+
exit_status = capture_shell_command_exit_status(command)
|
|
107
|
+
report_failed_command(command, exit_status) unless exit_status.zero?
|
|
108
|
+
exit_status
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def stream_step_command(step)
|
|
112
|
+
command = display_command(step)
|
|
113
|
+
exit_status = capture_step_command_exit_status(step)
|
|
114
|
+
report_failed_command(command, exit_status) unless exit_status.zero?
|
|
115
|
+
exit_status
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def capture_shell_command_exit_status(command)
|
|
119
|
+
exit_status = nil
|
|
120
|
+
|
|
121
|
+
Open3.popen2e(base_env, command, chdir: @target_dir) do |_stdin, output, wait_thread|
|
|
122
|
+
output.each_line { |line| @stdout.print(line) }
|
|
123
|
+
exit_status = wait_thread.value.exitstatus
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
exit_status
|
|
127
|
+
rescue StandardError => e
|
|
128
|
+
report_failed_command_start(command, e)
|
|
129
|
+
1
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def capture_step_command_exit_status(step)
|
|
133
|
+
exit_status = nil
|
|
134
|
+
|
|
135
|
+
Open3.popen2e(*step_command(step), chdir: @target_dir) do |_stdin, output, wait_thread|
|
|
136
|
+
output.each_line { |line| @stdout.print(line) }
|
|
137
|
+
exit_status = wait_thread.value.exitstatus
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
exit_status
|
|
141
|
+
rescue StandardError => e
|
|
142
|
+
report_failed_command_start(display_command(step), e)
|
|
143
|
+
1
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def base_env
|
|
147
|
+
# Pass through only the essentials so subprocess tools work correctly.
|
|
148
|
+
ENV.to_h.slice('PATH', 'HOME', 'LANG', 'TERM', 'SHELL',
|
|
149
|
+
'BUNDLE_GEMFILE', 'BUNDLE_PATH', 'GEM_HOME', 'GEM_PATH',
|
|
150
|
+
'RUBY_VERSION', 'RAILS_ENV', 'NODE_ENV',
|
|
151
|
+
'XDG_STATE_HOME', 'XDG_DATA_HOME', 'XDG_CONFIG_HOME',
|
|
152
|
+
'DEV_PORT', 'WORKTREE_DATABASE_SUFFIX')
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def yarn_lock_present?
|
|
156
|
+
File.exist?(File.join(@target_dir, 'yarn.lock'))
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def display_command(step)
|
|
160
|
+
env_prefix = step.fetch(:env, {}).map { |key, value| "#{key}=#{value}" }.join(' ')
|
|
161
|
+
command = step.fetch(:argv).join(' ')
|
|
162
|
+
[env_prefix, command].reject(&:empty?).join(' ')
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def step_command(step)
|
|
166
|
+
[base_env.merge(step.fetch(:env, {})), *step.fetch(:argv)]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def info(message)
|
|
170
|
+
@stdout.puts("→ #{message}")
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def report_failed_command(command, exit_status)
|
|
174
|
+
@stderr.puts("❌ Command failed (exit #{exit_status}): #{command}")
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def report_failed_command_start(command, error)
|
|
178
|
+
@stderr.puts("❌ Command failed to start: #{command} (#{error.message})")
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def credential_linking_enabled?
|
|
182
|
+
@configuration.link_credential_keys ||
|
|
183
|
+
@configuration.link_test_credential_key ||
|
|
184
|
+
@configuration.link_production_credential_key
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def credential_key_linker
|
|
188
|
+
CredentialKeyLinker.new(
|
|
189
|
+
target_dir: @target_dir,
|
|
190
|
+
peer_roots: @peer_roots,
|
|
191
|
+
configuration: @configuration
|
|
192
|
+
)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def print_credential_linking_messages(result)
|
|
196
|
+
result.messages.each { |message| info(" #{message}") }
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
# rubocop:enable Metrics/ClassLength
|
|
200
|
+
end
|
|
201
|
+
end
|
data/lib/rails/worktrees.rb
CHANGED
|
@@ -4,6 +4,8 @@ require_relative 'worktrees/version'
|
|
|
4
4
|
require_relative 'worktrees/configuration'
|
|
5
5
|
require_relative 'worktrees/application_configuration'
|
|
6
6
|
require_relative 'worktrees/env_bootstrapper'
|
|
7
|
+
require_relative 'worktrees/credential_key_linker'
|
|
8
|
+
require_relative 'worktrees/post_create_runner'
|
|
7
9
|
require_relative 'worktrees/command'
|
|
8
10
|
require_relative 'worktrees/cli'
|
|
9
11
|
require_relative 'worktrees/browser_command'
|
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.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Asjer Querido
|
|
@@ -63,13 +63,16 @@ files:
|
|
|
63
63
|
- lib/rails/worktrees/command/git_operations.rb
|
|
64
64
|
- lib/rails/worktrees/command/name_picking.rb
|
|
65
65
|
- lib/rails/worktrees/command/output.rb
|
|
66
|
+
- lib/rails/worktrees/command/post_create_support.rb
|
|
66
67
|
- lib/rails/worktrees/command/workspace_paths.rb
|
|
67
68
|
- lib/rails/worktrees/configuration.rb
|
|
69
|
+
- lib/rails/worktrees/credential_key_linker.rb
|
|
68
70
|
- lib/rails/worktrees/database_config_updater.rb
|
|
69
71
|
- lib/rails/worktrees/env_bootstrapper.rb
|
|
70
72
|
- lib/rails/worktrees/initializer_updater.rb
|
|
71
73
|
- lib/rails/worktrees/mise_toml_updater.rb
|
|
72
74
|
- lib/rails/worktrees/names/cities.txt
|
|
75
|
+
- lib/rails/worktrees/post_create_runner.rb
|
|
73
76
|
- lib/rails/worktrees/procfile_updater.rb
|
|
74
77
|
- lib/rails/worktrees/project_configuration_loader.rb
|
|
75
78
|
- lib/rails/worktrees/project_maintenance.rb
|