carson 4.3.0 → 4.3.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/.github/workflows/carson_policy.yml +0 -4
- data/API.md +2 -3
- data/MANUAL.md +8 -8
- data/README.md +1 -1
- data/RELEASE.md +31 -0
- data/VERSION +1 -1
- data/config/hooks/pre-commit +2 -17
- data/config/hooks/pre-push +9 -55
- data/lib/carson/adapters/agent.rb +1 -1
- data/lib/carson/config.rb +3 -14
- data/lib/carson/courier.rb +14 -17
- data/lib/carson/runtime/deliver.rb +1 -1
- data/lib/carson/runtime/local/onboard.rb +9 -43
- data/lib/carson/runtime/receive.rb +1 -1
- data/lib/carson/runtime/recover.rb +3 -3
- data/lib/carson/runtime/review/sweep_support.rb +1 -1
- data/lib/carson/runtime.rb +2 -5
- data/lib/carson/warehouse/vault.rb +15 -5
- data/lib/cli.rb +38 -70
- metadata +1 -2
- data/lib/carson/runtime/audit.rb +0 -603
data/lib/cli.rb
CHANGED
|
@@ -5,7 +5,7 @@ require "optparse"
|
|
|
5
5
|
module Carson
|
|
6
6
|
class CLI
|
|
7
7
|
PORTFOLIO_COMMANDS = %w[onboard offboard list refresh version].freeze
|
|
8
|
-
REPO_COMMANDS = %w[deliver receive sync status
|
|
8
|
+
REPO_COMMANDS = %w[deliver receive sync status prune housekeep worktree abandon recover review template setup checkin checkout].freeze
|
|
9
9
|
ALL_COMMANDS = ( PORTFOLIO_COMMANDS + REPO_COMMANDS ).freeze
|
|
10
10
|
|
|
11
11
|
def self.start( arguments:, repo_root:, tool_root:, output:, error: )
|
|
@@ -131,25 +131,19 @@ module Carson
|
|
|
131
131
|
OptionParser.new do |parser|
|
|
132
132
|
parser.banner = "Usage: carson <command> [options]\n carson <repo> <command> [options]"
|
|
133
133
|
parser.separator ""
|
|
134
|
-
parser.separator "
|
|
135
|
-
parser.separator ""
|
|
136
|
-
parser.separator "Portfolio commands:"
|
|
137
|
-
parser.separator " list List governed repositories"
|
|
138
|
-
parser.separator " onboard Register a repository for governance (requires repo path)"
|
|
139
|
-
parser.separator " offboard Remove a repository from governance (requires repo path)"
|
|
140
|
-
parser.separator " refresh Re-install hooks and configuration (all governed repos)"
|
|
141
|
-
parser.separator " version Show Carson version"
|
|
134
|
+
parser.separator "Keep agents from breaking main. Keep agents from breaking each other."
|
|
142
135
|
parser.separator ""
|
|
143
136
|
parser.separator "Agent workflow:"
|
|
144
|
-
parser.separator " checkin
|
|
145
|
-
parser.separator " deliver
|
|
137
|
+
parser.separator " checkin Get a fresh workbench"
|
|
138
|
+
parser.separator " deliver Accept into main and back up to remote"
|
|
146
139
|
parser.separator ""
|
|
147
|
-
parser.separator "
|
|
148
|
-
parser.separator "
|
|
149
|
-
parser.separator "
|
|
150
|
-
parser.separator "
|
|
140
|
+
parser.separator "Portfolio:"
|
|
141
|
+
parser.separator " onboard Start governing a repository"
|
|
142
|
+
parser.separator " offboard Stop governing a repository"
|
|
143
|
+
parser.separator " list Show governed repositories"
|
|
144
|
+
parser.separator " version Show Carson version"
|
|
151
145
|
parser.separator ""
|
|
152
|
-
parser.separator "Run `carson <command> --help` for details
|
|
146
|
+
parser.separator "Run `carson <command> --help` for details."
|
|
153
147
|
end
|
|
154
148
|
end
|
|
155
149
|
|
|
@@ -160,7 +154,7 @@ module Carson
|
|
|
160
154
|
return { command: :help }
|
|
161
155
|
end
|
|
162
156
|
return { command: "version" } if [ "--version", "-v" ].include?( first )
|
|
163
|
-
return { command: "
|
|
157
|
+
return { command: "status" } if arguments.empty?
|
|
164
158
|
|
|
165
159
|
nil
|
|
166
160
|
end
|
|
@@ -223,8 +217,6 @@ module Carson
|
|
|
223
217
|
parse_sync_command( arguments: arguments, error: error )
|
|
224
218
|
when "status"
|
|
225
219
|
parse_status_command( arguments: arguments, error: error )
|
|
226
|
-
when "audit"
|
|
227
|
-
parse_audit_command( arguments: arguments, error: error )
|
|
228
220
|
when "prune"
|
|
229
221
|
parse_prune_command( arguments: arguments, error: error )
|
|
230
222
|
when "housekeep"
|
|
@@ -290,7 +282,7 @@ module Carson
|
|
|
290
282
|
parser.banner = "Usage: carson onboard <REPO_PATH>"
|
|
291
283
|
parser.separator ""
|
|
292
284
|
parser.separator "Register a repository for Carson governance."
|
|
293
|
-
parser.separator "Detects the remote, installs hooks, applies templates
|
|
285
|
+
parser.separator "Detects the remote, installs hooks, and applies templates."
|
|
294
286
|
parser.separator ""
|
|
295
287
|
parser.separator "Examples:"
|
|
296
288
|
parser.separator " carson onboard ~/Dev/app Onboard a specific repository"
|
|
@@ -683,36 +675,6 @@ module Carson
|
|
|
683
675
|
{ command: :invalid }
|
|
684
676
|
end
|
|
685
677
|
|
|
686
|
-
# --- audit ---
|
|
687
|
-
|
|
688
|
-
def self.parse_audit_command( arguments:, error: )
|
|
689
|
-
options = { json: false }
|
|
690
|
-
audit_parser = OptionParser.new do |parser|
|
|
691
|
-
parser.banner = "Usage: carson audit [--json]"
|
|
692
|
-
parser.separator ""
|
|
693
|
-
parser.separator "Run pre-commit health checks on the repository."
|
|
694
|
-
parser.separator "Validates hooks, main-branch sync, PR status, and CI baseline."
|
|
695
|
-
parser.separator "Exits with a non-zero status when policy violations are found."
|
|
696
|
-
parser.separator ""
|
|
697
|
-
parser.separator "Options:"
|
|
698
|
-
parser.on( "--json", "Machine-readable JSON output" ) { options[ :json ] = true }
|
|
699
|
-
parser.separator ""
|
|
700
|
-
parser.separator "Examples:"
|
|
701
|
-
parser.separator " carson audit Check repository health (also the default command)"
|
|
702
|
-
parser.separator " carson audit --json Structured output for agent consumption"
|
|
703
|
-
end
|
|
704
|
-
audit_parser.parse!( arguments )
|
|
705
|
-
unless arguments.empty?
|
|
706
|
-
error.puts "#{BADGE} Unexpected arguments for audit: #{arguments.join( ' ' )}"
|
|
707
|
-
return { command: :invalid }
|
|
708
|
-
end
|
|
709
|
-
{ command: "audit", json: options[ :json ] }
|
|
710
|
-
rescue OptionParser::ParseError => exception
|
|
711
|
-
error.puts "#{BADGE} #{exception.message}"
|
|
712
|
-
error.puts audit_parser
|
|
713
|
-
{ command: :invalid }
|
|
714
|
-
end
|
|
715
|
-
|
|
716
678
|
# --- abandon ---
|
|
717
679
|
|
|
718
680
|
def self.parse_abandon_command( arguments:, error: )
|
|
@@ -813,20 +775,20 @@ module Carson
|
|
|
813
775
|
|
|
814
776
|
options = { json: false, title: nil, body_file: nil, commit_message: nil }
|
|
815
777
|
deliver_parser = OptionParser.new do |parser|
|
|
816
|
-
parser.banner = "Usage: carson deliver [--json] [--
|
|
778
|
+
parser.banner = "Usage: carson deliver [--json] [--commit MESSAGE]"
|
|
817
779
|
parser.separator ""
|
|
818
|
-
parser.separator "
|
|
819
|
-
parser.separator "Use --commit to
|
|
780
|
+
parser.separator "Accept committed work into main and sync to remote."
|
|
781
|
+
parser.separator "Use --commit to stage and commit all changes before delivery."
|
|
820
782
|
parser.separator ""
|
|
821
783
|
parser.separator "Options:"
|
|
822
784
|
parser.on( "--json", "Machine-readable JSON output" ) { options[ :json ] = true }
|
|
823
|
-
parser.on( "--title TITLE", "PR title (
|
|
824
|
-
parser.on( "--body-file PATH", "
|
|
825
|
-
parser.on( "--commit MESSAGE", "Commit all
|
|
785
|
+
parser.on( "--title TITLE", "PR title (remote workstyle only)" ) { |value| options[ :title ] = value }
|
|
786
|
+
parser.on( "--body-file PATH", "PR body file (remote workstyle only)" ) { |value| options[ :body_file ] = value }
|
|
787
|
+
parser.on( "--commit MESSAGE", "Commit all changes before delivery" ) { |value| options[ :commit_message ] = value }
|
|
826
788
|
parser.separator ""
|
|
827
789
|
parser.separator "Examples:"
|
|
828
790
|
parser.separator " carson deliver Deliver existing commits"
|
|
829
|
-
parser.separator " carson deliver --commit \"fix: harden flow\" Commit
|
|
791
|
+
parser.separator " carson deliver --commit \"fix: harden flow\" Commit then deliver"
|
|
830
792
|
end
|
|
831
793
|
deliver_parser.parse!( arguments )
|
|
832
794
|
if options.fetch( :commit_message, nil ).to_s.strip.empty? && !options.fetch( :commit_message, nil ).nil?
|
|
@@ -860,7 +822,7 @@ module Carson
|
|
|
860
822
|
parser.banner = "Usage: carson recover --check NAME [--json]"
|
|
861
823
|
parser.separator ""
|
|
862
824
|
parser.separator "Merge the current repair PR when one governance-owned required check is already red on the default branch."
|
|
863
|
-
parser.separator "Recovery is narrow: Carson verifies the baseline failure, keeps every other gate intact, and records
|
|
825
|
+
parser.separator "Recovery is narrow: Carson verifies the baseline failure, keeps every other gate intact, and records a recovery event."
|
|
864
826
|
parser.separator ""
|
|
865
827
|
parser.separator "Options:"
|
|
866
828
|
parser.on( "--check NAME", "Name of the governance-owned required check to recover" ) { |value| options[ :check_name ] = value }
|
|
@@ -994,8 +956,6 @@ module Carson
|
|
|
994
956
|
runtime.status!( json_output: parsed.fetch( :json, false ) )
|
|
995
957
|
when "setup"
|
|
996
958
|
runtime.setup!( cli_choices: parsed.fetch( :cli_choices, {} ) )
|
|
997
|
-
when "audit"
|
|
998
|
-
runtime.audit!( json_output: parsed.fetch( :json, false ) )
|
|
999
959
|
when "abandon"
|
|
1000
960
|
runtime.abandon!( target: parsed.fetch( :target ), json_output: parsed.fetch( :json, false ) )
|
|
1001
961
|
when "sync"
|
|
@@ -1023,15 +983,15 @@ module Carson
|
|
|
1023
983
|
when "template:apply"
|
|
1024
984
|
runtime.template_apply!( push_prep: parsed.fetch( :push_prep, false ) )
|
|
1025
985
|
when "deliver"
|
|
1026
|
-
if runtime.config.
|
|
1027
|
-
dispatch_deliver_locally( parsed: parsed, runtime: runtime )
|
|
1028
|
-
else
|
|
986
|
+
if runtime.config.bureau
|
|
1029
987
|
runtime.deliver!(
|
|
1030
988
|
title: parsed.fetch( :title, nil ),
|
|
1031
989
|
body_file: parsed.fetch( :body_file, nil ),
|
|
1032
990
|
commit_message: parsed.fetch( :commit_message, nil ),
|
|
1033
991
|
json_output: parsed.fetch( :json, false )
|
|
1034
992
|
)
|
|
993
|
+
else
|
|
994
|
+
dispatch_deliver_locally( parsed: parsed, runtime: runtime )
|
|
1035
995
|
end
|
|
1036
996
|
when "recover"
|
|
1037
997
|
runtime.recover!(
|
|
@@ -1102,6 +1062,14 @@ module Carson
|
|
|
1102
1062
|
json = parsed.fetch( :json, false )
|
|
1103
1063
|
output = runtime.output
|
|
1104
1064
|
|
|
1065
|
+
# Guard: cannot deliver from main itself.
|
|
1066
|
+
if parcel.on_main?( runtime.config.main_branch )
|
|
1067
|
+
result = { command: "deliver", status: "block",
|
|
1068
|
+
error: "Cannot deliver from #{runtime.config.main_branch}.",
|
|
1069
|
+
recovery: "carson checkin <name>" }
|
|
1070
|
+
return report_deliver( result: result, json: json, output: output )
|
|
1071
|
+
end
|
|
1072
|
+
|
|
1105
1073
|
# Step 1: Prepare.
|
|
1106
1074
|
prep = warehouse.prepare!( parcel, message: message )
|
|
1107
1075
|
unless prep[ :status ] == "ok"
|
|
@@ -1119,12 +1087,12 @@ module Carson
|
|
|
1119
1087
|
return report_deliver( result: accept, json: json, output: output )
|
|
1120
1088
|
end
|
|
1121
1089
|
|
|
1122
|
-
# Step 3: Courier
|
|
1123
|
-
courier = Courier.new( warehouse,
|
|
1124
|
-
|
|
1090
|
+
# Step 3: Courier syncs to remote.
|
|
1091
|
+
courier = Courier.new( warehouse, output: output )
|
|
1092
|
+
sync = courier.deliver( parcel )
|
|
1125
1093
|
|
|
1126
1094
|
# Combine results.
|
|
1127
|
-
result = accept.merge(
|
|
1095
|
+
result = accept.merge( sync.slice( :outcome, :synced, :sync_error ) )
|
|
1128
1096
|
result[ :command ] = "deliver"
|
|
1129
1097
|
result[ :outcome ] ||= "delivered"
|
|
1130
1098
|
report_deliver( result: result, json: json, output: output )
|
|
@@ -1146,9 +1114,9 @@ module Carson
|
|
|
1146
1114
|
when "ok"
|
|
1147
1115
|
output.puts "#{BADGE} #{result[ :branch ]} merged into main."
|
|
1148
1116
|
if result[ :synced ]
|
|
1149
|
-
output.puts "#{BADGE}
|
|
1150
|
-
elsif result[ :
|
|
1151
|
-
output.puts "#{BADGE}
|
|
1117
|
+
output.puts "#{BADGE} Synced to remote."
|
|
1118
|
+
elsif result[ :sync_error ]
|
|
1119
|
+
output.puts "#{BADGE} Sync failed."
|
|
1152
1120
|
output.puts " \u2192 git push"
|
|
1153
1121
|
end
|
|
1154
1122
|
when "block", "error"
|
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: 4.3.
|
|
4
|
+
version: 4.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hailei Wang
|
|
@@ -57,7 +57,6 @@ files:
|
|
|
57
57
|
- lib/carson/revision.rb
|
|
58
58
|
- lib/carson/runtime.rb
|
|
59
59
|
- lib/carson/runtime/abandon.rb
|
|
60
|
-
- lib/carson/runtime/audit.rb
|
|
61
60
|
- lib/carson/runtime/deliver.rb
|
|
62
61
|
- lib/carson/runtime/housekeep.rb
|
|
63
62
|
- lib/carson/runtime/list.rb
|