rails-worktrees 0.1.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 +7 -0
- data/.release-please-manifest.json +1 -0
- data/CHANGELOG.md +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +160 -0
- data/Rakefile +27 -0
- data/exe/wt +9 -0
- data/lefthook.yml +5 -0
- data/lib/generators/rails/worktrees/install_generator.rb +137 -0
- data/lib/generators/rails/worktrees/mise_follow_up.rb +37 -0
- data/lib/generators/rails/worktrees/templates/Procfile.dev.worktree.example.tt +4 -0
- data/lib/generators/rails/worktrees/templates/bin/wt +7 -0
- data/lib/generators/rails/worktrees/templates/rails_worktrees.rb.tt +21 -0
- data/lib/rails/worktrees/cli.rb +30 -0
- data/lib/rails/worktrees/command/environment_support.rb +47 -0
- data/lib/rails/worktrees/command/git_operations.rb +144 -0
- data/lib/rails/worktrees/command/name_picking.rb +156 -0
- data/lib/rails/worktrees/command/output.rb +131 -0
- data/lib/rails/worktrees/command/workspace_paths.rb +60 -0
- data/lib/rails/worktrees/command.rb +151 -0
- data/lib/rails/worktrees/configuration.rb +45 -0
- data/lib/rails/worktrees/database_config_updater.rb +129 -0
- data/lib/rails/worktrees/env_bootstrapper.rb +153 -0
- data/lib/rails/worktrees/names/cities.txt +96 -0
- data/lib/rails/worktrees/railtie.rb +8 -0
- data/lib/rails/worktrees/version.rb +7 -0
- data/lib/rails/worktrees.rb +32 -0
- data/mise.toml +5 -0
- data/release-please-config.json +12 -0
- data/sig/rails/worktrees.rbs +23 -0
- metadata +98 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rails
|
|
4
|
+
module Worktrees
|
|
5
|
+
# Safely patches common database.yml layouts for worktree suffixes.
|
|
6
|
+
class DatabaseConfigUpdater
|
|
7
|
+
Result = Struct.new(:content, :changed, :messages) do
|
|
8
|
+
def changed?
|
|
9
|
+
changed
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
SUFFIX_TEMPLATE = "<%= ENV.fetch('WORKTREE_DATABASE_SUFFIX', '') %>"
|
|
14
|
+
SUPPORTED_ENVIRONMENTS = %w[development test].freeze
|
|
15
|
+
DATABASE_LINE_PATTERN = /\A(\s*database:\s*)(.+?)(\s*(?:#.*)?\n?)\z/
|
|
16
|
+
SECTION_PATTERN = /\A([A-Za-z0-9_]+):(?:\s|$)/
|
|
17
|
+
|
|
18
|
+
def initialize(content:)
|
|
19
|
+
@content = content
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def call
|
|
23
|
+
state = { found: Hash.new(0), patched: 0, unsupported: [], environment: nil }
|
|
24
|
+
lines = @content.lines.map.with_index { |line, index| patch_line(line, index, state) }
|
|
25
|
+
|
|
26
|
+
Result.new(
|
|
27
|
+
lines.join,
|
|
28
|
+
state[:patched].positive?,
|
|
29
|
+
build_messages(state[:found], state[:patched], state[:unsupported])
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def patch_line(line, index, state)
|
|
36
|
+
state[:environment] = next_environment_for(line, state[:environment])
|
|
37
|
+
return line unless state[:environment]
|
|
38
|
+
|
|
39
|
+
match = line.match(DATABASE_LINE_PATTERN)
|
|
40
|
+
return line unless match
|
|
41
|
+
|
|
42
|
+
state[:found][state[:environment]] += 1
|
|
43
|
+
apply_patch(match, index, state)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def apply_patch(match, index, state)
|
|
47
|
+
patched_value = patch_database_value(match[2].strip, state[:environment])
|
|
48
|
+
|
|
49
|
+
if patched_value
|
|
50
|
+
state[:patched] += 1 unless patched_value == match[2].strip
|
|
51
|
+
"#{match[1]}#{patched_value}#{match[3]}"
|
|
52
|
+
else
|
|
53
|
+
state[:unsupported] << { environment: state[:environment], line: index + 1, value: match[2].strip }
|
|
54
|
+
match.string
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def next_environment_for(line, current_environment)
|
|
59
|
+
section_name = top_level_section_name(line)
|
|
60
|
+
return current_environment unless section_name
|
|
61
|
+
return section_name if SUPPORTED_ENVIRONMENTS.include?(section_name)
|
|
62
|
+
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def top_level_section_name(line)
|
|
67
|
+
return unless line.lstrip == line
|
|
68
|
+
|
|
69
|
+
match = line.match(SECTION_PATTERN)
|
|
70
|
+
match && match[1]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def patch_database_value(value, environment)
|
|
74
|
+
return value if value.include?('WORKTREE_DATABASE_SUFFIX')
|
|
75
|
+
return if value.include?('<%')
|
|
76
|
+
|
|
77
|
+
quote = value[/\A['"]/]
|
|
78
|
+
raw_value = quote ? value.delete_prefix(quote).delete_suffix(quote) : value
|
|
79
|
+
patched = patch_segmented_database_name(raw_value, environment) ||
|
|
80
|
+
patch_database_file_path(raw_value, environment)
|
|
81
|
+
return unless patched
|
|
82
|
+
|
|
83
|
+
quote ? "#{quote}#{patched}#{quote}" : patched
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def patch_segmented_database_name(raw_value, environment)
|
|
87
|
+
return unless raw_value.match?(/\A[\w-]+\z/)
|
|
88
|
+
|
|
89
|
+
segments = raw_value.split('_')
|
|
90
|
+
environment_index = segments.index(environment)
|
|
91
|
+
return unless environment_index
|
|
92
|
+
|
|
93
|
+
segments[environment_index] = "#{segments[environment_index]}#{SUFFIX_TEMPLATE}"
|
|
94
|
+
segments.join('_')
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def patch_database_file_path(raw_value, environment)
|
|
98
|
+
match = raw_value.match(
|
|
99
|
+
/\A(?<prefix>.*?)(?<environment>development|test)(?<tail>(?:[_-][\w-]+)*)(?<extension>\.[A-Za-z0-9.]+)\z/
|
|
100
|
+
)
|
|
101
|
+
return unless match
|
|
102
|
+
return unless match[:environment] == environment
|
|
103
|
+
|
|
104
|
+
[match[:prefix], match[:environment], SUFFIX_TEMPLATE, match[:tail], match[:extension]].join
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def build_messages(found_entries, patched_entries, unsupported_entries)
|
|
108
|
+
messages = [status_message(found_entries, patched_entries, unsupported_entries)].compact
|
|
109
|
+
return messages if unsupported_entries.empty?
|
|
110
|
+
|
|
111
|
+
line_numbers = unsupported_entries.map { |entry| entry[:line] }.join(', ')
|
|
112
|
+
messages << "Could not safely rewrite config/database.yml on line(s) #{line_numbers}. " \
|
|
113
|
+
"Add #{SUFFIX_TEMPLATE} to the development/test database name(s) manually."
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def status_message(found_entries, patched_entries, unsupported_entries)
|
|
117
|
+
total = found_entries.values.sum
|
|
118
|
+
if patched_entries.positive?
|
|
119
|
+
noun = patched_entries == 1 ? 'entry' : 'entries'
|
|
120
|
+
"Updated #{patched_entries} development/test database #{noun} to include WORKTREE_DATABASE_SUFFIX."
|
|
121
|
+
elsif total.positive? && unsupported_entries.empty?
|
|
122
|
+
'Development/test database names already include WORKTREE_DATABASE_SUFFIX.'
|
|
123
|
+
elsif total.zero?
|
|
124
|
+
'No development/test database entries matched a supported auto-update layout.'
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'zlib'
|
|
5
|
+
|
|
6
|
+
module Rails
|
|
7
|
+
module Worktrees
|
|
8
|
+
# Creates or updates a worktree-local .env with deterministic defaults.
|
|
9
|
+
# rubocop:disable Metrics/ClassLength
|
|
10
|
+
class EnvBootstrapper
|
|
11
|
+
Result = Struct.new(:changed, :env_path, :messages) do
|
|
12
|
+
def changed? = changed
|
|
13
|
+
|
|
14
|
+
attr_accessor :values
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
ENV_FILE_NAME = '.env'
|
|
18
|
+
|
|
19
|
+
def initialize(target_dir:, worktree_name:, configuration:)
|
|
20
|
+
@target_dir = target_dir
|
|
21
|
+
@worktree_name = worktree_name
|
|
22
|
+
@configuration = configuration
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def call(dry_run: false)
|
|
26
|
+
return disabled_result unless @configuration.bootstrap_env
|
|
27
|
+
|
|
28
|
+
lines = existing_env_lines
|
|
29
|
+
write_missing_updates(lines, resolved_values(lines), dry_run: dry_run)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def preview = result(false, [], resolved_values(existing_env_lines))
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def disabled_result = result(false, [], {})
|
|
37
|
+
|
|
38
|
+
def unchanged_result(values, dry_run: false)
|
|
39
|
+
message = if dry_run
|
|
40
|
+
"Would not change #{display_path(env_path)}; it already defines " \
|
|
41
|
+
'DEV_PORT and WORKTREE_DATABASE_SUFFIX'
|
|
42
|
+
else
|
|
43
|
+
"#{display_path(env_path)} already defines DEV_PORT and WORKTREE_DATABASE_SUFFIX"
|
|
44
|
+
end
|
|
45
|
+
result(false, [message], values)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def existing_env_lines = File.exist?(env_path) ? File.readlines(env_path, chomp: true) : []
|
|
49
|
+
|
|
50
|
+
def resolved_values(lines)
|
|
51
|
+
{
|
|
52
|
+
'DEV_PORT' => (env_value(lines, 'DEV_PORT') || allocate_dev_port).to_s,
|
|
53
|
+
'WORKTREE_DATABASE_SUFFIX' => env_value(lines, 'WORKTREE_DATABASE_SUFFIX') ||
|
|
54
|
+
format_worktree_database_suffix(@worktree_name)
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def write_missing_updates(existing_lines, values, dry_run: false)
|
|
59
|
+
updates = missing_updates(existing_lines, values)
|
|
60
|
+
return unchanged_result(values, dry_run: dry_run) if updates.empty?
|
|
61
|
+
return dry_run_bootstrap_result(values, updates) if dry_run
|
|
62
|
+
|
|
63
|
+
File.write(env_path, with_missing_entries(existing_lines, updates))
|
|
64
|
+
result(true, ["Bootstrapped #{display_path(env_path)} (#{formatted_updates(updates)})"], values)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def missing_updates(lines, values)
|
|
68
|
+
values.each_with_object({}) do |(key, value), updates|
|
|
69
|
+
updates[key] = value unless env_value(lines, key)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def result(changed, messages, values)
|
|
74
|
+
Result.new(changed, env_path, messages).tap do |bootstrap_result|
|
|
75
|
+
bootstrap_result.values = values
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def env_path = @env_path ||= File.join(@target_dir, ENV_FILE_NAME)
|
|
80
|
+
|
|
81
|
+
def with_missing_entries(lines, updates)
|
|
82
|
+
output = lines.dup
|
|
83
|
+
output << '' if output.any? && !output.last.empty?
|
|
84
|
+
updates.each { |key, value| output << "#{key}=#{value}" }
|
|
85
|
+
"#{output.join("\n")}\n"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def env_value(lines, key)
|
|
89
|
+
line = lines.reverse.find { |entry| entry.start_with?("#{key}=") }
|
|
90
|
+
value = line&.split('=', 2)&.last
|
|
91
|
+
value unless value&.empty?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def allocate_dev_port
|
|
95
|
+
ports = configured_port_range.to_a
|
|
96
|
+
raise ArgumentError, 'dev_port_range must contain at least one port' if ports.empty?
|
|
97
|
+
|
|
98
|
+
claimed_ports = claimed_peer_ports
|
|
99
|
+
candidate_ports(ports).find { |port| !claimed_ports.include?(port) } ||
|
|
100
|
+
raise(ArgumentError, "No available DEV_PORT values remain in #{configured_port_range}")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def dry_run_bootstrap_result(values, updates)
|
|
104
|
+
result(false, ["Would bootstrap #{display_path(env_path)} (#{formatted_updates(updates)})"], values)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def candidate_ports(ports)
|
|
108
|
+
start_index = Zlib.crc32(@worktree_name) % ports.length
|
|
109
|
+
ports.rotate(start_index)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def claimed_peer_ports
|
|
113
|
+
Dir.glob(File.join(peers_root, '*')).filter_map do |path|
|
|
114
|
+
next unless File.directory?(path)
|
|
115
|
+
next if File.expand_path(path) == File.expand_path(@target_dir)
|
|
116
|
+
|
|
117
|
+
port = env_value(peer_env_lines(path), 'DEV_PORT')
|
|
118
|
+
next unless port&.match?(/\A\d+\z/)
|
|
119
|
+
|
|
120
|
+
port.to_i
|
|
121
|
+
end.to_set
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def peer_env_lines(path)
|
|
125
|
+
env_file = File.join(path, ENV_FILE_NAME)
|
|
126
|
+
File.exist?(env_file) ? File.readlines(env_file, chomp: true) : []
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def peers_root = File.dirname(@target_dir)
|
|
130
|
+
|
|
131
|
+
def configured_port_range = @configuration.dev_port_range
|
|
132
|
+
|
|
133
|
+
def format_worktree_database_suffix(value)
|
|
134
|
+
suffix = value.downcase.gsub(/[^a-z0-9]+/, '_').gsub(/\A_+|_+\z/, '').squeeze('_')
|
|
135
|
+
suffix = suffix[0, @configuration.worktree_database_suffix_max_length]
|
|
136
|
+
suffix = suffix.to_s.sub(/_+\z/, '')
|
|
137
|
+
suffix = 'worktree' if suffix.empty?
|
|
138
|
+
"_#{suffix}"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def formatted_updates(updates) = updates.map { |key, value| "#{key}=#{value}" }.join(', ')
|
|
142
|
+
|
|
143
|
+
def display_path(path)
|
|
144
|
+
target_path = Pathname.new(path)
|
|
145
|
+
root_path = Pathname.new(@target_dir)
|
|
146
|
+
target_path.relative_path_from(root_path).to_s
|
|
147
|
+
rescue ArgumentError
|
|
148
|
+
path
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
# rubocop:enable Metrics/ClassLength
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# One worktree name per line. Keep names shell-safe: lowercase, hyphenated, no spaces.
|
|
2
|
+
amsterdam
|
|
3
|
+
athens
|
|
4
|
+
auckland
|
|
5
|
+
bangkok
|
|
6
|
+
barcelona
|
|
7
|
+
beijing
|
|
8
|
+
beirut
|
|
9
|
+
belgrade
|
|
10
|
+
berlin
|
|
11
|
+
bogota
|
|
12
|
+
boston
|
|
13
|
+
bratislava
|
|
14
|
+
brisbane
|
|
15
|
+
brussels
|
|
16
|
+
bucharest
|
|
17
|
+
budapest
|
|
18
|
+
busan
|
|
19
|
+
cairo
|
|
20
|
+
calgary
|
|
21
|
+
cape-town
|
|
22
|
+
casablanca
|
|
23
|
+
chicago
|
|
24
|
+
copenhagen
|
|
25
|
+
dakar
|
|
26
|
+
delhi
|
|
27
|
+
dubai
|
|
28
|
+
dublin
|
|
29
|
+
edinburgh
|
|
30
|
+
florence
|
|
31
|
+
geneva
|
|
32
|
+
helsinki
|
|
33
|
+
hong-kong
|
|
34
|
+
honolulu
|
|
35
|
+
istanbul
|
|
36
|
+
jakarta
|
|
37
|
+
johannesburg
|
|
38
|
+
kyoto
|
|
39
|
+
lagos
|
|
40
|
+
lima
|
|
41
|
+
lisbon
|
|
42
|
+
ljubljana
|
|
43
|
+
london
|
|
44
|
+
luxor
|
|
45
|
+
madrid
|
|
46
|
+
manila
|
|
47
|
+
marrakesh
|
|
48
|
+
melbourne
|
|
49
|
+
mexico-city
|
|
50
|
+
miami
|
|
51
|
+
milan
|
|
52
|
+
montreal
|
|
53
|
+
mumbai
|
|
54
|
+
munich
|
|
55
|
+
nairobi
|
|
56
|
+
naples
|
|
57
|
+
osaka
|
|
58
|
+
oslo
|
|
59
|
+
ottawa
|
|
60
|
+
palermo
|
|
61
|
+
paris
|
|
62
|
+
perth
|
|
63
|
+
porto
|
|
64
|
+
prague
|
|
65
|
+
quebec-city
|
|
66
|
+
reykjavik
|
|
67
|
+
riga
|
|
68
|
+
rio-de-janeiro
|
|
69
|
+
rome
|
|
70
|
+
rotterdam
|
|
71
|
+
salzburg
|
|
72
|
+
santiago
|
|
73
|
+
sao-paulo
|
|
74
|
+
seattle
|
|
75
|
+
seoul
|
|
76
|
+
shanghai
|
|
77
|
+
singapore
|
|
78
|
+
sofia
|
|
79
|
+
stockholm
|
|
80
|
+
sydney
|
|
81
|
+
taipei
|
|
82
|
+
tallinn
|
|
83
|
+
tbilisi
|
|
84
|
+
tokyo
|
|
85
|
+
toronto
|
|
86
|
+
turin
|
|
87
|
+
uppsala
|
|
88
|
+
utrecht
|
|
89
|
+
valencia
|
|
90
|
+
vancouver
|
|
91
|
+
venice
|
|
92
|
+
vienna
|
|
93
|
+
vilnius
|
|
94
|
+
warsaw
|
|
95
|
+
wellington
|
|
96
|
+
zurich
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'worktrees/version'
|
|
4
|
+
require_relative 'worktrees/configuration'
|
|
5
|
+
require_relative 'worktrees/env_bootstrapper'
|
|
6
|
+
require_relative 'worktrees/command'
|
|
7
|
+
require_relative 'worktrees/cli'
|
|
8
|
+
require_relative 'worktrees/database_config_updater'
|
|
9
|
+
|
|
10
|
+
module Rails
|
|
11
|
+
# Rails-specific git worktree helpers and installer support.
|
|
12
|
+
module Worktrees
|
|
13
|
+
class Error < StandardError; end
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
def configuration
|
|
17
|
+
@configuration ||= Configuration.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def configure
|
|
21
|
+
yield(configuration)
|
|
22
|
+
configuration
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def reset_configuration!
|
|
26
|
+
@configuration = Configuration.new
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
require_relative 'worktrees/railtie' if defined?(Rails::Railtie)
|
data/mise.toml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include-component-in-tag": false,
|
|
3
|
+
"packages": {
|
|
4
|
+
".": {
|
|
5
|
+
"initial-version": "0.1.0",
|
|
6
|
+
"release-type": "ruby",
|
|
7
|
+
"package-name": "rails-worktrees",
|
|
8
|
+
"version-file": "lib/rails/worktrees/version.rb",
|
|
9
|
+
"changelog-path": "CHANGELOG.md"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Worktrees
|
|
3
|
+
VERSION: String
|
|
4
|
+
|
|
5
|
+
class Error < StandardError
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class Configuration
|
|
9
|
+
attr_accessor bootstrap_env: bool
|
|
10
|
+
attr_accessor workspace_root: String?
|
|
11
|
+
attr_accessor branch_prefix: String
|
|
12
|
+
attr_accessor dev_port_range: ::Range[Integer]
|
|
13
|
+
attr_accessor name_sources_path: String
|
|
14
|
+
attr_accessor used_names_file: String
|
|
15
|
+
attr_accessor legacy_used_names_files: Array[String]
|
|
16
|
+
attr_accessor worktree_database_suffix_max_length: Integer
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.configuration: () -> Configuration
|
|
20
|
+
def self.configure: () { (Configuration) -> void } -> Configuration
|
|
21
|
+
def self.reset_configuration!: () -> Configuration
|
|
22
|
+
end
|
|
23
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails-worktrees
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Asjer Querido
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: railties
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.1'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '8.2'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '7.1'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '8.2'
|
|
32
|
+
description: Rails::Worktrees is a Ruby gem intended to support working with git worktrees
|
|
33
|
+
in Rails development workflows.
|
|
34
|
+
email:
|
|
35
|
+
- asjer@johnyontherun.com
|
|
36
|
+
executables:
|
|
37
|
+
- wt
|
|
38
|
+
extensions: []
|
|
39
|
+
extra_rdoc_files: []
|
|
40
|
+
files:
|
|
41
|
+
- ".release-please-manifest.json"
|
|
42
|
+
- CHANGELOG.md
|
|
43
|
+
- LICENSE.txt
|
|
44
|
+
- README.md
|
|
45
|
+
- Rakefile
|
|
46
|
+
- exe/wt
|
|
47
|
+
- lefthook.yml
|
|
48
|
+
- lib/generators/rails/worktrees/install_generator.rb
|
|
49
|
+
- lib/generators/rails/worktrees/mise_follow_up.rb
|
|
50
|
+
- lib/generators/rails/worktrees/templates/Procfile.dev.worktree.example.tt
|
|
51
|
+
- lib/generators/rails/worktrees/templates/bin/wt
|
|
52
|
+
- lib/generators/rails/worktrees/templates/rails_worktrees.rb.tt
|
|
53
|
+
- lib/rails/worktrees.rb
|
|
54
|
+
- lib/rails/worktrees/cli.rb
|
|
55
|
+
- lib/rails/worktrees/command.rb
|
|
56
|
+
- lib/rails/worktrees/command/environment_support.rb
|
|
57
|
+
- lib/rails/worktrees/command/git_operations.rb
|
|
58
|
+
- lib/rails/worktrees/command/name_picking.rb
|
|
59
|
+
- lib/rails/worktrees/command/output.rb
|
|
60
|
+
- lib/rails/worktrees/command/workspace_paths.rb
|
|
61
|
+
- lib/rails/worktrees/configuration.rb
|
|
62
|
+
- lib/rails/worktrees/database_config_updater.rb
|
|
63
|
+
- lib/rails/worktrees/env_bootstrapper.rb
|
|
64
|
+
- lib/rails/worktrees/names/cities.txt
|
|
65
|
+
- lib/rails/worktrees/railtie.rb
|
|
66
|
+
- lib/rails/worktrees/version.rb
|
|
67
|
+
- mise.toml
|
|
68
|
+
- release-please-config.json
|
|
69
|
+
- sig/rails/worktrees.rbs
|
|
70
|
+
homepage: https://github.com/asjer/rails-worktrees
|
|
71
|
+
licenses:
|
|
72
|
+
- MIT
|
|
73
|
+
metadata:
|
|
74
|
+
homepage_uri: https://github.com/asjer/rails-worktrees
|
|
75
|
+
source_code_uri: https://github.com/asjer/rails-worktrees
|
|
76
|
+
changelog_uri: https://github.com/asjer/rails-worktrees/blob/main/CHANGELOG.md
|
|
77
|
+
rubygems_mfa_required: 'true'
|
|
78
|
+
post_install_message: "\n============================================\n Thank you
|
|
79
|
+
for installing rails-worktrees! \U0001F389\n\n Run the installer:\n $ bin/rails
|
|
80
|
+
generate rails:worktrees:install\n\n Docs: https://github.com/asjer/rails-worktrees\n============================================\n\n"
|
|
81
|
+
rdoc_options: []
|
|
82
|
+
require_paths:
|
|
83
|
+
- lib
|
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: 3.2.0
|
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '0'
|
|
94
|
+
requirements: []
|
|
95
|
+
rubygems_version: 3.6.9
|
|
96
|
+
specification_version: 4
|
|
97
|
+
summary: Helpers for managing Rails application git worktrees.
|
|
98
|
+
test_files: []
|