Module: Carson::Runtime::Audit
- Included in:
- Carson::Runtime
- Defined in:
- lib/carson/runtime/audit.rb
Instance Method Summary collapse
- #audit! ⇒ Object
-
#check! ⇒ Object
Thin focused command: show required-check status for the current branch’s open PR.
Instance Method Details
#audit! ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 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 |
# File 'lib/carson/runtime/audit.rb', line 6 def audit! fingerprint_status = block_if_outsider_fingerprints! return fingerprint_status unless fingerprint_status.nil? unless head_exists? puts_line "No commits yet — audit skipped for initial commit." return EXIT_OK end audit_state = "ok" audit_concise_problems = [] puts_verbose "" puts_verbose "[Repository]" puts_verbose "root: #{repo_root}" puts_verbose "current_branch: #{current_branch}" puts_verbose "" puts_verbose "[Working Tree]" puts_verbose git_capture!( "status", "--short", "--branch" ).strip puts_verbose "" puts_verbose "[Hooks]" hooks_ok = hooks_health_report unless hooks_ok audit_state = "block" audit_concise_problems << "Hooks: mismatch — run carson prepare." end puts_verbose "" puts_verbose "[Main Sync Status]" ahead_count, behind_count, main_error = main_sync_counts if main_error puts_verbose "main_vs_remote_main: unknown" puts_verbose "WARN: unable to calculate main sync status (#{main_error})." audit_state = "attention" if audit_state == "ok" elsif ahead_count.positive? puts_verbose "main_vs_remote_main_ahead: #{ahead_count}" puts_verbose "main_vs_remote_main_behind: #{behind_count}" puts_verbose "ACTION: local #{config.main_branch} is ahead of #{config.git_remote}/#{config.main_branch} by #{ahead_count} commit#{plural_suffix( count: ahead_count )}; reset local drift before commit/push workflows." audit_state = "block" audit_concise_problems << "Main sync (#{config.git_remote}): ahead by #{ahead_count} — git fetch #{config.git_remote}, or carson setup to switch remote." elsif behind_count.positive? puts_verbose "main_vs_remote_main_ahead: #{ahead_count}" puts_verbose "main_vs_remote_main_behind: #{behind_count}" puts_verbose "ACTION: local #{config.main_branch} is behind #{config.git_remote}/#{config.main_branch} by #{behind_count} commit#{plural_suffix( count: behind_count )}; run carson sync." audit_state = "attention" if audit_state == "ok" audit_concise_problems << "Main sync (#{config.git_remote}): behind by #{behind_count} — run carson sync." else puts_verbose "main_vs_remote_main_ahead: 0" puts_verbose "main_vs_remote_main_behind: 0" puts_verbose "ACTION: local #{config.main_branch} is in sync with #{config.git_remote}/#{config.main_branch}." end puts_verbose "" puts_verbose "[PR and Required Checks (gh)]" monitor_report = pr_and_check_report audit_state = "attention" if audit_state == "ok" && monitor_report.fetch( :status ) != "ok" puts_verbose "" puts_verbose "[Default Branch CI Baseline (gh)]" default_branch_baseline = default_branch_ci_baseline_report audit_state = "block" if default_branch_baseline.fetch( :status ) == "block" audit_state = "attention" if audit_state == "ok" && default_branch_baseline.fetch( :status ) != "ok" scope_guard = print_scope_integrity_guard audit_state = "attention" if audit_state == "ok" && scope_guard.fetch( :status ) == "attention" write_and_print_pr_monitor_report( report: monitor_report.merge( default_branch_baseline: default_branch_baseline, audit_status: audit_state ) ) puts_verbose "" puts_verbose "[Audit Result]" puts_verbose "status: #{audit_state}" puts_verbose( audit_state == "block" ? "ACTION: local policy block must be resolved before commit/push." : "ACTION: no local hard block detected." ) unless verbose? audit_concise_problems.each { |problem| puts_line problem } puts_line "Audit: #{audit_state}" end audit_state == "block" ? EXIT_BLOCK : EXIT_OK end |
#check! ⇒ Object
Thin focused command: show required-check status for the current branch’s open PR. Always exits 0 for pending or passing so callers never see a false “Error: Exit code 8”.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/carson/runtime/audit.rb', line 83 def check! unless head_exists? puts_line "Checks: no commits yet." return EXIT_OK end unless gh_available? puts_line "Checks: gh CLI not available." return EXIT_ERROR end pr_stdout, pr_stderr, pr_success, = gh_run( "pr", "view", current_branch, "--json", "number,title,url" ) unless pr_success error_text = gh_error_text( stdout_text: pr_stdout, stderr_text: pr_stderr, fallback: "no open PR for branch #{current_branch}" ) puts_line "Checks: #{error_text}." return EXIT_ERROR end pr_data = JSON.parse( pr_stdout ) pr_number = pr_data[ "number" ].to_s checks_stdout, checks_stderr, checks_success, checks_exit = gh_run( "pr", "checks", pr_number, "--required", "--json", "name,state,bucket,workflow,link" ) if checks_stdout.to_s.strip.empty? error_text = gh_error_text( stdout_text: checks_stdout, stderr_text: checks_stderr, fallback: "required checks unavailable" ) puts_line "Checks: #{error_text}." return EXIT_ERROR end checks_data = JSON.parse( checks_stdout ) pending = checks_data.select { |e| e[ "bucket" ].to_s == "pending" } failing = checks_data.select { |e| check_entry_failing?( entry: e ) } total = checks_data.count # gh exits 8 when required checks are still pending (not a failure). is_pending = !checks_success && checks_exit == 8 if failing.any? puts_line "Checks: FAIL (#{failing.count} of #{total} failing)." normalise_check_entries( entries: failing ).each { |e| puts_line " #{e.fetch( :workflow )} / #{e.fetch( :name )} #{e.fetch( :link )}".strip } return EXIT_BLOCK end if is_pending || pending.any? puts_line "Checks: pending (#{total - pending.count} of #{total} complete)." return EXIT_OK end puts_line "Checks: all passing (#{total} required)." EXIT_OK rescue JSON::ParserError => e puts_line "Checks: invalid gh response (#{e.})." EXIT_ERROR end |