yamine 0.15.0 → 0.15.2
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/CHANGELOG.md +29 -0
- data/lib/yamine/cli/worktree.rb +30 -5
- data/lib/yamine/proxy.rb +8 -2
- data/lib/yamine/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: f0fb00156c920d8b49a4116be04c671904877e26cb75816d3f7d05d899f413be
|
|
4
|
+
data.tar.gz: 28c31ed6f7e03fd453b9fa00c1372c36701b675b015c9de906223934b3ade84f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 69ce5134433ef830e42ba29420ab0ab17a6f39ec39cb885e534cbdae485cc6360270ad45b6e31b99191988a0f2d3fd6d20b5a0073df9469478ebeddc0f092c03
|
|
7
|
+
data.tar.gz: 037bc4d5fd9ac1767304c1a6bee32572bc28a95cd64fde42414c6ff38624dd74c3a0be05966bd2d32a91e5c3664ba99ac1a5fac50fcd81b1a673a48e75b990b6
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.15.1] — 2026-09-22
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Stale merged worktrees now lose their branch too.** A worktree whose
|
|
8
|
+
directory was already gone was pruned from git, but its branch was
|
|
9
|
+
left behind — so `remove` and `clean` reported success while the
|
|
10
|
+
merged branch lingered, unlike a normal teardown. Stale entries now
|
|
11
|
+
delete a merged branch the same way (`git branch -d` after the
|
|
12
|
+
prune), and an unmerged branch is kept with the reason said out loud
|
|
13
|
+
unless `--force`. Regression coverage pins all three: stale + merged
|
|
14
|
+
deletes, stale + unmerged keeps, and `clean` doing the same sweep.
|
|
15
|
+
|
|
3
16
|
## [0.15.0] — 2026-09-15
|
|
4
17
|
|
|
5
18
|
### Changed
|
|
@@ -16,6 +29,22 @@
|
|
|
16
29
|
boot. Interleaving matches the foreman/without-yamine experience; a
|
|
17
30
|
per-process opt-in can be added later if needed.
|
|
18
31
|
|
|
32
|
+
## [0.14.3] — 2026-09-15
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- **WebSocket upgrades carry the same forwarded headers as every other
|
|
37
|
+
request.** Upgrade requests (ActionCable, Turbo Streams over cable)
|
|
38
|
+
were piped to the backend byte-for-byte, so `X-Forwarded-Proto`,
|
|
39
|
+
`X-Forwarded-For`, and `X-Forwarded-Host` never arrived — the one
|
|
40
|
+
request class that skipped `set_forwarded`. An app behind the proxy
|
|
41
|
+
then saw a `wss://` connection as plain `http`, and Rails' ActionCable
|
|
42
|
+
origin check (Origin vs. scheme + Host) compared
|
|
43
|
+
`https://app.localhost` against `http://app.localhost` and refused the
|
|
44
|
+
socket with "Request origin not allowed". Upgrades now run the same
|
|
45
|
+
`set_forwarded` path as every other request before the head is
|
|
46
|
+
forwarded; the bytes after the header block still pipe raw.
|
|
47
|
+
|
|
19
48
|
## [0.14.2] — 2026-09-15
|
|
20
49
|
|
|
21
50
|
### Added
|
data/lib/yamine/cli/worktree.rb
CHANGED
|
@@ -210,7 +210,7 @@ module Yamine
|
|
|
210
210
|
end
|
|
211
211
|
|
|
212
212
|
unless entry.exists?
|
|
213
|
-
abandon(ctx, repo, entry)
|
|
213
|
+
abandon(ctx, repo, entry, force: opts[:force])
|
|
214
214
|
return
|
|
215
215
|
end
|
|
216
216
|
|
|
@@ -251,6 +251,7 @@ module Yamine
|
|
|
251
251
|
|
|
252
252
|
failures = 0
|
|
253
253
|
changed = false
|
|
254
|
+
stale = []
|
|
254
255
|
plan.each do |step|
|
|
255
256
|
case step[0]
|
|
256
257
|
when :drop_db
|
|
@@ -266,12 +267,14 @@ module Yamine
|
|
|
266
267
|
failures += 1
|
|
267
268
|
end
|
|
268
269
|
when :prune
|
|
270
|
+
stale << step[1]
|
|
269
271
|
changed = true
|
|
270
272
|
when :keep
|
|
271
273
|
puts " kept #{step[1]} — #{step[2]}"
|
|
272
274
|
end
|
|
273
275
|
end
|
|
274
276
|
Worktrees.prune(repo) if repo
|
|
277
|
+
stale.each { |entry| delete_stale_branch(repo, entry) } if repo
|
|
275
278
|
resync_hosts(ctx) if repo && changed
|
|
276
279
|
ran = plan.count { |s| %i[drop_db teardown prune].include?(s[0]) }
|
|
277
280
|
summary = "Cleaned #{ran} item(s)"
|
|
@@ -285,7 +288,7 @@ module Yamine
|
|
|
285
288
|
case action
|
|
286
289
|
when :drop_db then "drop database #{subject} (#{reason} is gone)"
|
|
287
290
|
when :teardown then "remove worktree #{subject.path} (#{reason})"
|
|
288
|
-
when :prune then "prune stale git entry #{subject}"
|
|
291
|
+
when :prune then "prune stale git entry #{subject.path}"
|
|
289
292
|
when :keep then "keep #{subject} — #{reason}"
|
|
290
293
|
end
|
|
291
294
|
end
|
|
@@ -303,7 +306,7 @@ module Yamine
|
|
|
303
306
|
next if entry.bare || entry.main?
|
|
304
307
|
|
|
305
308
|
unless entry.exists?
|
|
306
|
-
plan << Plan.new(:prune, entry
|
|
309
|
+
plan << Plan.new(:prune, entry)
|
|
307
310
|
next
|
|
308
311
|
end
|
|
309
312
|
if Worktrees.dirty?(entry.path, ignore: LOCAL_CONFIG_FILES)
|
|
@@ -370,8 +373,10 @@ module Yamine
|
|
|
370
373
|
end
|
|
371
374
|
|
|
372
375
|
# A worktree whose directory is already gone: nothing to stop or
|
|
373
|
-
# remove, just its database claim
|
|
374
|
-
|
|
376
|
+
# remove, just its database claim, the stale git entry, and — when
|
|
377
|
+
# the branch is merged — the branch itself, matching what a normal
|
|
378
|
+
# removal would have done.
|
|
379
|
+
def abandon(ctx, repo, entry, force: false)
|
|
375
380
|
map = Database.load_map(ctx.store.dir)
|
|
376
381
|
claim = claim_for(map, entry.path)
|
|
377
382
|
if claim
|
|
@@ -379,6 +384,26 @@ module Yamine
|
|
|
379
384
|
end
|
|
380
385
|
Worktrees.prune(repo)
|
|
381
386
|
puts " pruned #{entry.path} (directory was already gone)"
|
|
387
|
+
delete_stale_branch(repo, entry, force: force)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# Prune first so git will allow the delete; an unmerged branch is
|
|
391
|
+
# kept unless force, exactly as teardown does for a live worktree.
|
|
392
|
+
def delete_stale_branch(repo, entry, force: false)
|
|
393
|
+
return unless entry.branch && Worktrees.branch_exists?(repo, entry.branch)
|
|
394
|
+
|
|
395
|
+
merged = Worktrees.merged?(repo, entry.branch,
|
|
396
|
+
into: Worktrees.default_branch(repo))
|
|
397
|
+
if force || merged
|
|
398
|
+
flag = force ? "-D" : "-d"
|
|
399
|
+
_out, status = Open3.capture2("git", "branch", flag, entry.branch,
|
|
400
|
+
chdir: repo, err: File::NULL)
|
|
401
|
+
if status&.success?
|
|
402
|
+
puts " deleted branch #{entry.branch}"
|
|
403
|
+
return
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
puts " kept branch #{entry.branch} (git refuses to delete an unmerged branch)"
|
|
382
407
|
end
|
|
383
408
|
|
|
384
409
|
# The teardown shared by `remove` and `clean`. Returns true when
|
data/lib/yamine/proxy.rb
CHANGED
|
@@ -320,12 +320,18 @@ module Yamine
|
|
|
320
320
|
|
|
321
321
|
def handle_upgrade(sock, head, buf)
|
|
322
322
|
routes = cached_routes
|
|
323
|
-
|
|
323
|
+
method, target, headers = parse_head(head)
|
|
324
324
|
entry = route(headers["host"].to_s, routes)
|
|
325
325
|
return unless entry
|
|
326
326
|
|
|
327
|
+
# Upgrades carry the same forwarded headers as every other request:
|
|
328
|
+
# an app behind the proxy (ActionCable's origin check) reads the
|
|
329
|
+
# scheme from X-Forwarded-Proto, and a verbatim head would tell a
|
|
330
|
+
# wss:// connection it arrived as http.
|
|
331
|
+
set_forwarded(headers, sock, tls: @tls)
|
|
332
|
+
|
|
327
333
|
backend = dial(entry)
|
|
328
|
-
backend.write(
|
|
334
|
+
backend.write(rebuild_head(method, target, headers))
|
|
329
335
|
backend.write(buf) unless buf.empty?
|
|
330
336
|
pipe_both(sock, backend)
|
|
331
337
|
rescue SystemCallError, OpenSSL::SSL::SSLError, IOError => e
|
data/lib/yamine/version.rb
CHANGED