rails-worktrees 0.7.3 → 0.7.4

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: 4ca5bda1caef0299d08ce62341cebeb9fe2cf35be6acb2c84438af5cfcb11f8e
4
- data.tar.gz: c3278894ecf06ef752d15ff56ab64c47b56bdb2f0cf39e0773012ce71eda8823
3
+ metadata.gz: 4eed6634afda26cca90bd9f6e2540a7ace8f865ec53f97a283fc873e137cffe8
4
+ data.tar.gz: 6a2541a2a026af4ed0ccd8e14f3d1ceac78e0da7c5e4d1fc01c1fb6d4b34e0ad
5
5
  SHA512:
6
- metadata.gz: bdb2583a6e1f1e8785599a31907c5a69c50eed1a8ebc9909fa139a59d4dd0ae5df0e941403aff68b3742f3c5c565461021418320b7a98054e7c710b491f3405a
7
- data.tar.gz: 9ee5cc2bbd46b0b1cf152576be8269ee03bc0b3f749c3d878ce01976a6166fb2de2d4862dd4789b45569161e3f04802cdb2864a2973514a11f9184f0923e3fd4
6
+ metadata.gz: 0a8cf44f39ec11d98faa0d7e3b18badb5b1c4a8dcb3c31c67a0f26d4442656554cb5658275ccc96df69364d5a46572ab2408f57ea08deb31a0568bf284daf2da
7
+ data.tar.gz: 588ba219467bee9baa350d06d44a8eaf56fc1eab7e361bb1ff233cd7b9efa1e0e7041ad9f96d90d1bd059ae378789388caf0d4b7c2556cd29b6f7c28cfc63c07
@@ -1 +1 @@
1
- {".":"0.7.3"}
1
+ {".":"0.7.4"}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.4](https://github.com/asjer/rails-worktrees/compare/v0.7.3...v0.7.4) (2026-08-15)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **wt:** bootstrap Ruby through mise for legacy wrappers ([#45](https://github.com/asjer/rails-worktrees/issues/45)) ([b3326ab](https://github.com/asjer/rails-worktrees/commit/b3326ab737fb814d826a1b4870433028a455f582))
9
+
3
10
  ## [0.7.3](https://github.com/asjer/rails-worktrees/compare/v0.7.2...v0.7.3) (2026-07-08)
4
11
 
5
12
 
data/README.md CHANGED
@@ -23,7 +23,7 @@ The generated initializer writes app config under `Rails.application.config.x.ra
23
23
 
24
24
  The installer adds:
25
25
 
26
- - `bin/wt` — a thin wrapper that executes the gem-owned CLI
26
+ - `bin/wt` — a mise-aware bootstrap wrapper that executes the gem-owned CLI
27
27
  - `bin/ob` — an optional browser helper generated by `--browser` or `--yolo`
28
28
  - `config/initializers/rails_worktrees.rb` — optional configuration
29
29
  - `Procfile.dev.worktree.example` — a copy-paste helper for `${DEV_PORT:-3000}` in `Procfile.dev` on regular installs
@@ -160,6 +160,37 @@ bin/wt prune --dry-run
160
160
 
161
161
  `bin/wt update` is intentionally conservative: it only applies safe file-based fixes for managed templates and supported config shapes. It does **not** delete branches, remove worktrees, or rewrite ambiguous custom files automatically.
162
162
 
163
+ ### Updating old `bin/wt` wrappers
164
+
165
+ Versions before 0.7.1 generated `bin/wt` as a Ruby shebang wrapper. On hosts where Ruby is provided by mise but not already on `PATH`, that legacy wrapper can fail with `/usr/bin/env: ruby: No such file or directory` before rails-worktrees can activate mise.
166
+
167
+ Use the current gem executable once to repair the app-owned wrapper. Scope mise discovery to the checkout and treat in-repository mise configs as trusted for this recovery shell, so `mise exec` loads Ruby from the same configuration the repaired wrapper will use:
168
+
169
+ ```bash
170
+ # From the Rails app root
171
+ root=$(pwd -P)
172
+ trust_root=$(
173
+ unset GIT_DIR GIT_WORK_TREE GIT_COMMON_DIR GIT_INDEX_FILE \
174
+ GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES
175
+ git -C "$root" rev-parse --show-toplevel 2>/dev/null || printf '%s' "$root"
176
+ )
177
+ trust_root=$(cd "$trust_root" && pwd -P)
178
+ MISE_CEILING_PATHS=$(dirname "$trust_root")
179
+ MISE_TRUSTED_CONFIG_PATHS="$trust_root"
180
+ export MISE_CEILING_PATHS MISE_TRUSTED_CONFIG_PATHS
181
+
182
+ mise exec -C "$root" -- ruby -v
183
+ mise exec -C "$root" -- gem install rails-worktrees --no-document
184
+ mise exec -C "$root" -- ruby -e 'load Gem.bin_path("rails-worktrees", "wt")' -- update --dry-run "$root"
185
+ mise exec -C "$root" -- ruby -e 'load Gem.bin_path("rails-worktrees", "wt")' -- update "$root"
186
+ git status --short
187
+ git diff --stat
188
+ ```
189
+
190
+ Review the diff before committing. `wt update` applies every safe managed maintenance fix it finds, so the resulting commit can include `bin/wt` plus other generated installer drift such as the initializer, database configuration, Procfile, Puma config, mise config, or `bin/ob`.
191
+
192
+ New installs and repaired apps use a bash bootstrap wrapper that activates mise from the app root before loading Ruby/Bundler, trusting mise configs only inside the repository root and bounding discovery above the checkout. That covers app-local, in-repository higher-scope, local override, and environment-specific mise configuration without trusting an unrelated caller directory or configs above the checkout. The wrapper also falls back to the globally installed `wt` executable for bootstrap-safe commands such as `wt setup --dry-run` when the app bundle is incomplete.
193
+
163
194
 
164
195
  ### Interactive prompts
165
196
 
@@ -47,18 +47,29 @@ fi
47
47
  WT_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
48
48
  WT_SCRIPT_PATH="$WT_SCRIPT_DIR/$(basename "${BASH_SOURCE[0]}")"
49
49
  WT_APP_ROOT="$(cd "$WT_SCRIPT_DIR/.." && pwd -P)"
50
- WT_MISE_CONFIG=""
51
50
 
52
- if [ -f "$WT_APP_ROOT/mise.toml" ]; then
53
- WT_MISE_CONFIG="$WT_APP_ROOT/mise.toml"
54
- elif [ -f "$WT_APP_ROOT/.mise.toml" ]; then
55
- WT_MISE_CONFIG="$WT_APP_ROOT/.mise.toml"
51
+ wt_path_within() {
52
+ case "$1" in
53
+ "$2"|"$2"/*) return 0 ;;
54
+ *) return 1 ;;
55
+ esac
56
+ }
57
+
58
+ WT_MISE_TRUST_ROOT="$WT_APP_ROOT"
59
+ if command -v git >/dev/null 2>&1; then
60
+ WT_GIT_ROOT="$(unset GIT_DIR GIT_WORK_TREE GIT_COMMON_DIR GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES; git -C "$WT_APP_ROOT" rev-parse --show-toplevel 2>/dev/null || true)"
61
+ if [ -n "$WT_GIT_ROOT" ]; then
62
+ WT_GIT_ROOT="$(cd "$WT_GIT_ROOT" && pwd -P)"
63
+ wt_path_within "$WT_APP_ROOT" "$WT_GIT_ROOT" && WT_MISE_TRUST_ROOT="$WT_GIT_ROOT"
64
+ fi
56
65
  fi
66
+ WT_MISE_CEILING_PATH="$(dirname "$WT_MISE_TRUST_ROOT")"
57
67
 
58
- if [ -n "$WT_MISE_CONFIG" ] && [ -z "${RAILS_WORKTREES_BOOTSTRAPPED:-}" ] && command -v mise >/dev/null 2>&1; then
59
- mise trust "$WT_MISE_CONFIG" >/dev/null || true
68
+ if [ -z "${RAILS_WORKTREES_BOOTSTRAPPED:-}" ] && command -v mise >/dev/null 2>&1; then
69
+ export MISE_CEILING_PATHS="$WT_MISE_CEILING_PATH"
70
+ export MISE_TRUSTED_CONFIG_PATHS="$WT_MISE_TRUST_ROOT"
60
71
  export RAILS_WORKTREES_BOOTSTRAPPED=1
61
- exec mise exec -- "$WT_SCRIPT_PATH" "$@"
72
+ exec mise exec -C "$WT_APP_ROOT" -- "$WT_SCRIPT_PATH" "$@"
62
73
  fi
63
74
 
64
75
  export BUNDLE_GEMFILE="${BUNDLE_GEMFILE:-$WT_APP_ROOT/Gemfile}"
@@ -214,7 +214,8 @@ module Rails
214
214
  validate_update_args!
215
215
  announce_dry_run if dry_run?
216
216
 
217
- current_root = resolve_repository_context[:current_root]
217
+ repository_root = resolve_repository_context[:current_root]
218
+ current_root = update_target_root(repository_root)
218
219
  report = project_maintenance_report(current_root)
219
220
  updated_count = 0
220
221
  identical_count = 0
@@ -258,11 +259,25 @@ module Rails
258
259
  end
259
260
 
260
261
  def validate_update_args!
261
- raise Error, 'Usage: wt update [--dry-run]' unless @argv.length == 1
262
+ raise Error, 'Usage: wt update [--dry-run] [path]' unless [1, 2].include?(@argv.length)
262
263
  raise Error, 'The --force flag is only supported with wt remove.' if force?
263
264
  raise Error, 'The --skip-setup flag is only supported when creating a worktree.' if skip_setup?
264
265
  end
265
266
 
267
+ def update_target_root(repository_root)
268
+ return repository_root unless @argv[1]
269
+
270
+ target_root = canonical_path(File.expand_path(@argv[1], @cwd))
271
+ raise Error, "Update target does not exist: #{target_root}" unless File.directory?(target_root)
272
+
273
+ assert_within_root!(
274
+ target_root,
275
+ repository_root,
276
+ "Refusing to update a path outside the current Git repository: #{target_root}"
277
+ )
278
+ target_root
279
+ end
280
+
266
281
  def announce_prune_candidates(candidates)
267
282
  info("Found #{candidates.length} merged worktree#{'s' unless candidates.length == 1} created by wt:")
268
283
  end
@@ -7,7 +7,7 @@ module Rails
7
7
  class MiseEnvironment
8
8
  Result = Struct.new(:env, :messages)
9
9
 
10
- CONFIG_FILES = %w[mise.toml .mise.toml].freeze
10
+ CONFIG_FILES = %w[mise.toml .mise.toml mise.local.toml .mise.local.toml].freeze
11
11
 
12
12
  def initialize(target_dir:, env:)
13
13
  @target_dir = target_dir
@@ -164,18 +164,66 @@ module Rails
164
164
  attr_reader :runtime_env
165
165
 
166
166
  def resolved_runtime_env(dry_run:)
167
- env = shell_env.merge(@bootstrapped_env)
167
+ env = shell_env.merge(@bootstrapped_env).merge(target_mise_scope_env)
168
168
  return env if dry_run
169
169
 
170
- env.merge(toolchain_env)
170
+ env.merge(toolchain_env(env))
171
171
  end
172
172
 
173
- def toolchain_env
174
- result = MiseEnvironment.new(target_dir: @target_dir, env: shell_env.merge(@bootstrapped_env)).call
173
+ def toolchain_env(env)
174
+ result = MiseEnvironment.new(target_dir: @target_dir, env: env).call
175
175
  result.messages.each { |message| info(message) }
176
176
  result.env
177
177
  end
178
178
 
179
+ def target_mise_scope_env
180
+ trust_root = target_git_root || canonical_target_dir
181
+
182
+ {
183
+ 'MISE_CEILING_PATHS' => File.dirname(trust_root),
184
+ 'MISE_TRUSTED_CONFIG_PATHS' => trust_root
185
+ }
186
+ end
187
+
188
+ def target_git_root
189
+ stdout_str, status = capture_target_git_root
190
+ return nil unless status.success?
191
+
192
+ root = File.realpath(stdout_str.strip)
193
+ target_within_root?(root) ? root : nil
194
+ rescue Errno::ENOENT, Errno::ENOTDIR
195
+ nil
196
+ end
197
+
198
+ def capture_target_git_root
199
+ stdout_str, _stderr_str, status = Open3.capture3(
200
+ git_discovery_env,
201
+ 'git', '-C', @target_dir, 'rev-parse', '--show-toplevel'
202
+ )
203
+ [stdout_str, status]
204
+ end
205
+
206
+ def git_discovery_env
207
+ shell_env.merge(
208
+ 'GIT_DIR' => nil,
209
+ 'GIT_WORK_TREE' => nil,
210
+ 'GIT_COMMON_DIR' => nil,
211
+ 'GIT_INDEX_FILE' => nil,
212
+ 'GIT_OBJECT_DIRECTORY' => nil,
213
+ 'GIT_ALTERNATE_OBJECT_DIRECTORIES' => nil
214
+ )
215
+ end
216
+
217
+ def target_within_root?(root)
218
+ canonical_target_dir.start_with?("#{root}#{File::SEPARATOR}") || canonical_target_dir == root
219
+ end
220
+
221
+ def canonical_target_dir
222
+ @canonical_target_dir ||= File.realpath(@target_dir)
223
+ rescue Errno::ENOENT
224
+ File.expand_path(@target_dir)
225
+ end
226
+
179
227
  def yarn_lock_present?
180
228
  File.exist?(File.join(@target_dir, 'yarn.lock'))
181
229
  end
@@ -1,5 +1,5 @@
1
1
  module Rails
2
2
  module Worktrees
3
- VERSION = '0.7.3'.freeze
3
+ VERSION = '0.7.4'.freeze
4
4
  end
5
5
  end
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.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asjer Querido