carson 3.15.0 → 3.15.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: 83272d790537e52d22639bbf4831f772496b9ffa5938b23da6d2865ae73d8e38
4
- data.tar.gz: ff4d8db79fc54bcd12d74a4c6c74332861ea58dc3fef78f93b3188237d27c772
3
+ metadata.gz: b350c2bb611f2357a7ea9a422b8c1c836f551dc22a33c6ed70c9f0409425d208
4
+ data.tar.gz: 1333080091cb8e945df2c22e3349b4445124dc4ee856dd10de7b557a284c94df
5
5
  SHA512:
6
- metadata.gz: 655f2cb1f8caa036e96dc17e4e360ced9256840ee5f2050d33e9f72f4187a2f0d8fefbe27d82ff2da8e3bd21f5c8bb460886bf31af922818fa74efeb3fe9d59f
7
- data.tar.gz: 44490df6057142b3f58745ac24041e501207599684d9a10816ee505ed192c681661fd4e23003d637a6ccf69f4a86efbd6d754ada2d6079ee99db89b431133495
6
+ metadata.gz: ba0030df2fde050f0fdd971970b4fe0c4053cad7d293076e6f11c6262feb012a7d7466a547a8812f4befbd6364bfed64e06af4308ab84a802611a3c15e16ee57
7
+ data.tar.gz: ca7d8bab1f94b3981d224d00aeedc388beba5c33f04f54494f5b9ef91e3f693b41440462a298e8c06146773b628a003d9b203ec2d0b3c06918502bfd961056f6
data/RELEASE.md CHANGED
@@ -5,6 +5,15 @@ Release-note scope rule:
5
5
  - `RELEASE.md` records only version deltas, breaking changes, and migration actions.
6
6
  - Operational usage guides live in `MANUAL.md` and `API.md`.
7
7
 
8
+ ## 3.15.1
9
+
10
+ ### What changed
11
+
12
+ - **Dead worktree reaping** — `housekeep` now reaps dead worktrees before pruning. Unblocks prune for branches held by stale worktrees.
13
+ - Two-layer dead check: fast content-absorbed test, then definitive merged-PR evidence via GitHub API. Covers simple merges and rebase/squash cases where main has evolved.
14
+ - Safe removal only — refuses dirty working trees (`git worktree remove` without `--force`).
15
+ - Deletes the local branch after removal (unless protected).
16
+
8
17
  ## 3.15.0
9
18
 
10
19
  ### What changed
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.15.0
1
+ 3.15.1
@@ -1,8 +1,9 @@
1
- # Housekeeping — sync + prune for a repository.
1
+ # Housekeeping — sync, reap dead worktrees, and prune for a repository.
2
2
  # carson housekeep <repo> — serve one repo by name or path.
3
3
  # carson housekeep — serve the repo you are standing in.
4
4
  # carson housekeep --all — serve all governed repos.
5
5
  require "json"
6
+ require "open3"
6
7
  require "stringio"
7
8
 
8
9
  module Carson
@@ -41,6 +42,50 @@ module Carson
41
42
  housekeep_finish( result: result, exit_code: failed.zero? ? EXIT_OK : EXIT_ERROR, json_output: json_output, results: results, succeeded: succeeded, failed: failed )
42
43
  end
43
44
 
45
+ # Removes dead worktrees — those with a merged PR and a clean working tree.
46
+ # Unblocks prune for the branches they hold.
47
+ # Two-layer dead check:
48
+ # 1. Fast: branch content is fully absorbed into main (covers simple cases).
49
+ # 2. Definitive: a merged PR exists for this branch (covers rebase/squash where
50
+ # main has since evolved the same files).
51
+ def reap_dead_worktrees!
52
+ return unless gh_available?
53
+
54
+ main_root = main_worktree_root
55
+ worktrees = worktree_list
56
+
57
+ worktrees.each do |wt|
58
+ path = wt.fetch( :path )
59
+ branch = wt.fetch( :branch, nil )
60
+ next if path == main_root
61
+ next unless branch
62
+ next if cwd_inside_worktree?( worktree_path: path )
63
+
64
+ # Dead check: absorbed into main, or merged PR evidence.
65
+ dead = branch_absorbed_into_main?( branch: branch )
66
+ unless dead
67
+ tip_sha = git_capture!( "rev-parse", "--verify", branch ).strip rescue nil
68
+ if tip_sha
69
+ merged_pr, = merged_pr_for_branch( branch: branch, branch_tip_sha: tip_sha )
70
+ dead = !merged_pr.nil?
71
+ end
72
+ end
73
+ next unless dead
74
+
75
+ # Remove the worktree (no --force: refuses if dirty working tree).
76
+ _, _, rm_success, = git_run( "worktree", "remove", path )
77
+ next unless rm_success
78
+
79
+ puts_verbose "reaped dead worktree: #{File.basename( path )} (branch: #{branch})"
80
+
81
+ # Delete the local branch now that no worktree holds it.
82
+ if !config.protected_branches.include?( branch )
83
+ git_run( "branch", "-D", branch )
84
+ puts_verbose "deleted branch: #{branch}"
85
+ end
86
+ end
87
+ end
88
+
44
89
  private
45
90
 
46
91
  # Runs sync + prune on one repo and returns the exit code directly.
@@ -64,7 +109,10 @@ module Carson
64
109
  rt = Runtime.new( repo_root: repo_path, tool_root: tool_root, out: buf, err: err_buf, verbose: verbose? )
65
110
 
66
111
  sync_status = rt.sync!
67
- prune_status = rt.prune! if sync_status == EXIT_OK
112
+ if sync_status == EXIT_OK
113
+ rt.reap_dead_worktrees!
114
+ prune_status = rt.prune!
115
+ end
68
116
 
69
117
  ok = sync_status == EXIT_OK && prune_status == EXIT_OK
70
118
  unless verbose? || silent
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carson
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.15.0
4
+ version: 3.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hailei Wang