rails-worktrees 0.2.0 → 0.2.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: 5cf1debd660652a5429a2d5485e944006685268b423866a96e15af71f9cb3471
4
- data.tar.gz: 14f6a3f5efaa6b829026b3d4d085c9b55d09236cb7b610bafa8f8834a534fb5b
3
+ metadata.gz: 971ba5f8f872a37a91d2e8c1755bf838db8bf67a767dbfba1b105b727440d9b7
4
+ data.tar.gz: dd0441f61442afffc29b7ab5f70968abd0c35c59e2731247cc55ddeae6e18265
5
5
  SHA512:
6
- metadata.gz: e16d066bfb55c97b959e92b4c25d1b2ac08404a728cadf077852a937a1a4c00ea17ca0c08dcfecc571654f836ba0aeccc6f81b08b6a96f7a4443093681d3b25d
7
- data.tar.gz: f7fdc3e954463fed68f62934d153fbe4b086fb86f4be97c8f8e172b54c0bcc4d402587b99c2b171cc024f7ef53be14e950da311399e49ef0a491d696ac15dc64
6
+ metadata.gz: 1e77b1961db51bcaca110efe1b8c9c6c96e848b523f30e158cc55c94550023fb85289b124ec859abd6957542ae0fcc4e20a63f793985b87ea5a03e2302b9748a
7
+ data.tar.gz: 5955435a25990d85b834e9c22d3c37d9621cab21a69dac6c6b9e038e763bc8346a8f6a23886f37098285cd6f055496417f85b34f8351e9f5b4d3e6115b429753
@@ -1 +1 @@
1
- {".":"0.2.0"}
1
+ {".":"0.2.1"}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.1](https://github.com/asjer/rails-worktrees/compare/v0.2.0...v0.2.1) (2026-03-30)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **puma:** add missing `DEV_PORT` support to config/puma.rb ([3fd71a0](https://github.com/asjer/rails-worktrees/commit/3fd71a04d79732bed4cf626951abe06ddbc01153))
9
+
3
10
  ## [0.2.0](https://github.com/asjer/rails-worktrees/compare/v0.1.1...v0.2.0) (2026-03-30)
4
11
 
5
12
 
data/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  ```bash
14
14
  bundle add rails-worktrees
15
15
  bin/rails generate worktrees:install
16
- # or, to apply the common Procfile.dev + mise follow-ups automatically:
16
+ # or, to apply the common Procfile.dev + Puma + mise follow-ups automatically:
17
17
  bin/rails generate worktrees:install --yolo
18
18
  ```
19
19
 
@@ -27,6 +27,7 @@ The installer adds:
27
27
  With `--yolo`, the installer also:
28
28
 
29
29
  - replaces the existing `web:` entry in `Procfile.dev` with the DEV_PORT-aware command when `Procfile.dev` already exists
30
+ - updates `config/puma.rb` to use `port ENV['DEV_PORT'] || ENV.fetch('PORT', 3000)` when it still uses a supported default `PORT` binding
30
31
  - updates `mise.toml` or `.mise.toml` to load `.env` from `[env]` when either file already exists
31
32
 
32
33
  ## Usage
@@ -122,17 +123,20 @@ When `bin/wt` creates a worktree it writes a worktree-local `.env` with:
122
123
 
123
124
  Existing `.env` values are never overwritten.
124
125
 
125
- By default, the installer does **not** edit your `Procfile.dev` or `mise` config. It generates `Procfile.dev.worktree.example` with a ready-to-copy line:
126
+ By default, the installer does **not** edit your `Procfile.dev`, `config/puma.rb`, or `mise` config. It generates `Procfile.dev.worktree.example` with a ready-to-copy line:
126
127
 
127
128
  ```text
128
129
  web: env RUBY_DEBUG_OPEN=true bin/rails server -b 0.0.0.0 -p ${DEV_PORT:-3000}
129
130
  ```
130
131
 
131
- If you run `bin/rails generate worktrees:install --yolo`, the installer applies the two common follow-ups for you when the files already exist:
132
+ If you run `bin/rails generate worktrees:install --yolo`, the installer applies the three common follow-ups for you when the files already exist:
132
133
 
133
134
  - replace the existing `web:` entry in `Procfile.dev`
135
+ - update `config/puma.rb` to `port ENV['DEV_PORT'] || ENV.fetch('PORT', 3000)` when it still uses a supported default `PORT` binding
134
136
  - add `_.file = ".env"` to the `[env]` section of `mise.toml` or `.mise.toml`
135
137
 
138
+ On a regular install, the follow-up message also suggests the same `config/puma.rb` edit when Puma still uses the default `PORT` binding.
139
+
136
140
  Use a project-local env loader like `mise` with `_.file = ".env"` to keep values scoped per-worktree.
137
141
 
138
142
  ## Development
@@ -154,7 +158,7 @@ This smoke test:
154
158
  - creates a temporary Rails app from a compatible Rails version
155
159
  - installs `rails-worktrees` from the current checkout path
156
160
  - runs `bin/rails generate worktrees:install --yolo`
157
- - verifies `bin/wt`, the generated initializer, the Procfile example, yolo updates to `Procfile.dev` and `mise.toml`, `config/database.yml` patching, and worktree `.env` bootstrapping
161
+ - verifies `bin/wt`, the generated initializer, the Procfile example, yolo updates to `Procfile.dev`, `config/puma.rb`, and `mise.toml`, `config/database.yml` patching, and worktree `.env` bootstrapping
158
162
  - creates a temporary bare `origin` and confirms `bin/wt smoke-branch` creates a real worktree
159
163
 
160
164
  By default, the script cleans up all temp directories after the run. Set `KEEP_SMOKE_TEST_ARTIFACTS=1` to keep them around for debugging, or set `RAILS_WORKTREES_SMOKE_RAILS_VERSION` to try a different compatible Rails version.
@@ -0,0 +1,45 @@
1
+ module Rails
2
+ module Worktrees
3
+ module Generators
4
+ # Detects config/puma.rb setups that should prefer the worktree-local DEV_PORT.
5
+ module PumaFollowUp
6
+ private
7
+
8
+ def puma_follow_up_notes_text
9
+ return '' unless suggest_puma_dev_port_update?
10
+
11
+ [
12
+ '',
13
+ ' Tip:',
14
+ ' Detected config/puma.rb. To bind Puma to the worktree-local DEV_PORT,',
15
+ ' consider changing the port line to:',
16
+ " #{::Rails::Worktrees::PumaConfigUpdater::STANDARD_PORT_LINE}"
17
+ ].join("\n")
18
+ end
19
+
20
+ def suggest_puma_dev_port_update?
21
+ existing_puma_config_path && puma_update_result.status == :updated
22
+ end
23
+
24
+ def puma_update_result
25
+ return missing_puma_update_result unless existing_puma_config_path
26
+
27
+ ::Rails::Worktrees::PumaConfigUpdater.new(content: File.read(existing_puma_config_path)).call
28
+ end
29
+
30
+ def missing_puma_update_result
31
+ ::Rails::Worktrees::PumaConfigUpdater::Result.new(nil, false, :skip, [])
32
+ end
33
+
34
+ def puma_config_path
35
+ File.join(destination_root, 'config/puma.rb')
36
+ end
37
+
38
+ def existing_puma_config_path
39
+ path = puma_config_path
40
+ File.file?(path) ? path : nil
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -2,9 +2,11 @@ require 'open3'
2
2
  require 'rails/generators'
3
3
 
4
4
  require_relative '../../rails/worktrees/mise_follow_up'
5
+ require_relative '../../rails/worktrees/puma_follow_up'
5
6
  require_relative '../../../rails/worktrees/database_config_updater'
6
7
  require_relative '../../../rails/worktrees/procfile_updater'
7
8
  require_relative '../../../rails/worktrees/mise_toml_updater'
9
+ require_relative '../../../rails/worktrees/puma_config_updater'
8
10
 
9
11
  module Worktrees
10
12
  module Generators
@@ -12,6 +14,7 @@ module Worktrees
12
14
  # rubocop:disable Metrics/ClassLength
13
15
  class InstallGenerator < ::Rails::Generators::Base
14
16
  include ::Rails::Worktrees::Generators::MiseFollowUp
17
+ include ::Rails::Worktrees::Generators::PumaFollowUp
15
18
 
16
19
  namespace 'worktrees:install'
17
20
  desc 'Installs bin/wt, a Rails::Worktrees initializer, and updates config/database.yml when safe.'
@@ -19,7 +22,7 @@ module Worktrees
19
22
  class_option :conductor, type: :boolean, default: false,
20
23
  desc: 'Configure the installer for ~/Sites/conductor/workspaces'
21
24
  class_option :yolo, type: :boolean, default: false,
22
- desc: 'Apply common Procfile.dev and mise .env follow-up edits when safe'
25
+ desc: 'Apply common Procfile.dev, config/puma.rb, and mise .env follow-up edits when safe'
23
26
 
24
27
  FOLLOW_UP_TEMPLATE = <<~TEXT.freeze
25
28
  ============================================
@@ -55,6 +58,7 @@ module Worktrees
55
58
  return unless options[:yolo]
56
59
 
57
60
  update_procfile
61
+ update_puma_config
58
62
  update_mise_toml
59
63
  end
60
64
 
@@ -92,6 +96,10 @@ module Worktrees
92
96
  File.join(destination_root, 'Procfile.dev')
93
97
  end
94
98
 
99
+ def puma_config_path
100
+ File.join(destination_root, 'config/puma.rb')
101
+ end
102
+
95
103
  def mise_toml_paths
96
104
  [
97
105
  File.join(destination_root, 'mise.toml'),
@@ -113,6 +121,10 @@ module Worktrees
113
121
  "\n#{format(FOLLOW_UP_TEMPLATE, installed: installed_items_text, notes: follow_up_notes_text)}"
114
122
  end
115
123
 
124
+ def follow_up_notes_text
125
+ [super, puma_follow_up_notes_text].join
126
+ end
127
+
116
128
  def installed_items_text
117
129
  items = [
118
130
  ' • bin/wt',
@@ -152,6 +164,18 @@ module Worktrees
152
164
  announce_updater_result('Procfile.dev', result)
153
165
  end
154
166
 
167
+ def update_puma_config
168
+ unless File.exist?(puma_config_path)
169
+ say_status(:skip, 'config/puma.rb not found', :yellow)
170
+ say('Skipped config/puma.rb yolo update because the file does not exist yet.')
171
+ return
172
+ end
173
+
174
+ result = ::Rails::Worktrees::PumaConfigUpdater.new(content: File.read(puma_config_path)).call
175
+ File.write(puma_config_path, result.content) if result.changed?
176
+ announce_updater_result('config/puma.rb', result)
177
+ end
178
+
155
179
  def update_mise_toml
156
180
  path = first_mise_toml_path
157
181
  return announce_missing_mise_toml unless path
@@ -0,0 +1,91 @@
1
+ module Rails
2
+ module Worktrees
3
+ # Safely updates config/puma.rb to bind Puma to the worktree-local DEV_PORT.
4
+ class PumaConfigUpdater
5
+ Result = Struct.new(:content, :changed, :status, :messages) do
6
+ def changed?
7
+ changed
8
+ end
9
+ end
10
+
11
+ STANDARD_PORT_LINE = "port ENV['DEV_PORT'] || ENV.fetch('PORT', 3000)".freeze
12
+ CURRENT_PORT_PATTERN = /\A\s*port\s+ENV\.fetch\(["']PORT["'],\s*3000\)\s*(?:#.*)?\z/
13
+ LEGACY_PORT_PATTERN = /\A\s*port\s+ENV\.fetch\(["']PORT["']\)\s*\{\s*3000\s*\}\s*(?:#.*)?\z/
14
+ PORT_LINE_PATTERN = /\A\s*port\s+/
15
+ DEV_PORT_ACCESS_PATTERN = /ENV\[(["'])DEV_PORT\1\]/
16
+ DEV_PORT_FETCH_PATTERN = /ENV\.fetch\((["'])DEV_PORT\1(?:\s*,|\s*\))/
17
+
18
+ def initialize(content:)
19
+ @content = content
20
+ end
21
+
22
+ def call
23
+ lines = @content.lines(chomp: true)
24
+ return identical_result(@content) if dev_port_configured?(lines)
25
+
26
+ port_line_indexes = supported_port_line_indexes(lines)
27
+ return skip_result if port_line_indexes.empty?
28
+
29
+ updated_content = rebuild_content(
30
+ replace_port_lines(lines, port_line_indexes),
31
+ trailing_newline: @content.end_with?("\n")
32
+ )
33
+
34
+ updated_result(updated_content)
35
+ end
36
+
37
+ private
38
+
39
+ def updated_result(content)
40
+ Result.new(content, true, :updated, ['Updated config/puma.rb to prefer DEV_PORT before PORT.'])
41
+ end
42
+
43
+ def identical_result(content)
44
+ Result.new(content, false, :identical, ['config/puma.rb already uses DEV_PORT-aware port binding.'])
45
+ end
46
+
47
+ def skip_result
48
+ Result.new(
49
+ @content,
50
+ false,
51
+ :skip,
52
+ ['No supported Puma port binding found in config/puma.rb; update it manually if needed.']
53
+ )
54
+ end
55
+
56
+ def dev_port_configured?(lines)
57
+ lines.any? do |line|
58
+ line.match?(PORT_LINE_PATTERN) &&
59
+ (line.match?(DEV_PORT_ACCESS_PATTERN) || line.match?(DEV_PORT_FETCH_PATTERN))
60
+ end
61
+ end
62
+
63
+ def supported_port_line_indexes(lines)
64
+ lines.each_index.select { |index| supported_port_line?(lines[index]) }
65
+ end
66
+
67
+ def supported_port_line?(line)
68
+ line.match?(CURRENT_PORT_PATTERN) || line.match?(LEGACY_PORT_PATTERN)
69
+ end
70
+
71
+ def replace_port_lines(lines, port_line_indexes)
72
+ lines.dup.tap do |updated_lines|
73
+ port_line_indexes.each do |index|
74
+ original_line = lines[index]
75
+ indent = original_line[/\A\s*/]
76
+ trailing_comment = original_line[/(\s*#.*)\z/, 1].to_s
77
+
78
+ updated_lines[index] = "#{indent}#{STANDARD_PORT_LINE}#{trailing_comment}"
79
+ end
80
+ end
81
+ end
82
+
83
+ def rebuild_content(lines, trailing_newline:)
84
+ content = lines.join("\n")
85
+ return content if content.empty? || !trailing_newline
86
+
87
+ "#{content}\n"
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,5 +1,5 @@
1
1
  module Rails
2
2
  module Worktrees
3
- VERSION = '0.2.0'.freeze
3
+ VERSION = '0.2.1'.freeze
4
4
  end
5
5
  end
@@ -8,6 +8,7 @@ require_relative 'worktrees/cli'
8
8
  require_relative 'worktrees/database_config_updater'
9
9
  require_relative 'worktrees/procfile_updater'
10
10
  require_relative 'worktrees/mise_toml_updater'
11
+ require_relative 'worktrees/puma_config_updater'
11
12
 
12
13
  module Rails
13
14
  # 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.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asjer Querido
@@ -46,6 +46,7 @@ files:
46
46
  - exe/wt
47
47
  - lefthook.yml
48
48
  - lib/generators/rails/worktrees/mise_follow_up.rb
49
+ - lib/generators/rails/worktrees/puma_follow_up.rb
49
50
  - lib/generators/rails/worktrees/templates/Procfile.dev.worktree.example.tt
50
51
  - lib/generators/rails/worktrees/templates/bin/wt
51
52
  - lib/generators/rails/worktrees/templates/rails_worktrees.rb.tt
@@ -64,6 +65,7 @@ files:
64
65
  - lib/rails/worktrees/mise_toml_updater.rb
65
66
  - lib/rails/worktrees/names/cities.txt
66
67
  - lib/rails/worktrees/procfile_updater.rb
68
+ - lib/rails/worktrees/puma_config_updater.rb
67
69
  - lib/rails/worktrees/railtie.rb
68
70
  - lib/rails/worktrees/version.rb
69
71
  - mise.toml