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 +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +7 -0
- data/README.md +32 -1
- data/lib/generators/rails/worktrees/templates/bin/wt +19 -8
- data/lib/rails/worktrees/command.rb +17 -2
- data/lib/rails/worktrees/mise_environment.rb +1 -1
- data/lib/rails/worktrees/post_create_runner.rb +52 -4
- data/lib/rails/worktrees/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4eed6634afda26cca90bd9f6e2540a7ace8f865ec53f97a283fc873e137cffe8
|
|
4
|
+
data.tar.gz: 6a2541a2a026af4ed0ccd8e14f3d1ceac78e0da7c5e4d1fc01c1fb6d4b34e0ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a8cf44f39ec11d98faa0d7e3b18badb5b1c4a8dcb3c31c67a0f26d4442656554cb5658275ccc96df69364d5a46572ab2408f57ea08deb31a0568bf284daf2da
|
|
7
|
+
data.tar.gz: 588ba219467bee9baa350d06d44a8eaf56fc1eab7e361bb1ff233cd7b9efa1e0e7041ad9f96d90d1bd059ae378789388caf0d4b7c2556cd29b6f7c28cfc63c07
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{".":"0.7.
|
|
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
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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 [ -
|
|
59
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|