Module: Carson::Runtime::Housekeep

Included in:
Carson::Runtime
Defined in:
lib/carson/runtime/housekeep.rb

Instance Method Summary collapse

Instance Method Details

#housekeep!(json_output: false) ⇒ Object

Serves the current repo: sync + prune.



13
14
15
# File 'lib/carson/runtime/housekeep.rb', line 13

def housekeep!( json_output: false )
	housekeep_one( repo_path: repo_root, json_output: json_output )
end

#housekeep_all!(json_output: false) ⇒ Object

Knocks each governed repo’s gate in turn.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/carson/runtime/housekeep.rb', line 29

def housekeep_all!( json_output: false )
	repos = config.govern_repos
	if repos.empty?
		result = { command: "housekeep", status: "error", error: "No governed repositories configured.", recovery: "Run carson onboard in each repo to register." }
		return housekeep_finish( result: result, exit_code: EXIT_ERROR, json_output: json_output )
	end

	results = []
	repos.each { |repo_path| results << housekeep_one_entry( repo_path: repo_path, silent: json_output ) }

	succeeded = results.count { |r| r[ :status ] == "ok" }
	failed = results.count { |r| r[ :status ] != "ok" }
	result = { command: "housekeep", status: failed.zero? ? "ok" : "partial", repos: results, succeeded: succeeded, failed: failed }
	housekeep_finish( result: result, exit_code: failed.zero? ? EXIT_OK : EXIT_ERROR, json_output: json_output, results: results, succeeded: succeeded, failed: failed )
end

#housekeep_target!(target:, json_output: false) ⇒ Object

Resolves a target name to a governed repo, then serves it.



18
19
20
21
22
23
24
25
26
# File 'lib/carson/runtime/housekeep.rb', line 18

def housekeep_target!( target:, json_output: false )
	repo_path = resolve_governed_repo( target: target )
	unless repo_path
		result = { command: "housekeep", status: "error", error: "Not a governed repository: #{target}", recovery: "Run carson repos to see governed repositories." }
		return housekeep_finish( result: result, exit_code: EXIT_ERROR, json_output: json_output )
	end

	housekeep_one( repo_path: repo_path, json_output: json_output )
end

#reap_dead_worktrees!Object

Removes dead worktrees — those whose content is on main or with merged PR evidence. Unblocks prune for the branches they hold. Two-layer dead check:

1. Content-absorbed: delegates to sweep_stale_worktrees! (shared, no gh needed).
2. Merged PR evidence: covers rebase/squash where main has since evolved
   the same files (requires gh).


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/carson/runtime/housekeep.rb', line 51

def reap_dead_worktrees!
	# Layer 1: sweep agent-owned worktrees whose content is on main.
	sweep_stale_worktrees!

	# Layer 2: merged PR evidence for remaining worktrees.
	return unless gh_available?

	main_root = main_worktree_root
	worktree_list.each do |wt|
		path = wt.fetch( :path )
		branch = wt.fetch( :branch, nil )
		next if path == main_root
		next unless branch
		next if cwd_inside_worktree?( worktree_path: path )

		# Missing directory: worktree was destroyed externally.
		# Prune the stale entry and delete the branch immediately.
		unless Dir.exist?( path )
			git_run( "worktree", "prune" )
			puts_verbose "reaped stale worktree entry: #{File.basename( path )} (branch: #{branch})"
			if !config.protected_branches.include?( branch )
				git_run( "branch", "-D", branch )
				puts_verbose "deleted branch: #{branch}"
			end
			next
		end

		tip_sha = git_capture!( "rev-parse", "--verify", branch ).strip rescue nil
		next unless tip_sha

		merged_pr, = merged_pr_for_branch( branch: branch, branch_tip_sha: tip_sha )
		next if merged_pr.nil?

		# Remove the worktree (no --force: refuses if dirty working tree).
		_, _, rm_success, = git_run( "worktree", "remove", path )
		next unless rm_success

		puts_verbose "reaped dead worktree: #{File.basename( path )} (branch: #{branch})"

		# Delete the local branch now that no worktree holds it.
		if !config.protected_branches.include?( branch )
			git_run( "branch", "-D", branch )
			puts_verbose "deleted branch: #{branch}"
		end
	end
end