Class: Aidp::Watch::ReviewProcessor

Inherits:
Object
  • Object
show all
Includes:
MessageDisplay
Defined in:
lib/aidp/watch/review_processor.rb

Overview

Handles the aidp-review label trigger by performing multi-persona code review and posting categorized findings back to the PR.

Constant Summary collapse

DEFAULT_REVIEW_LABEL =

Default label names

"aidp-review"
COMMENT_HEADER =
"## 🤖 AIDP Code Review"

Constants included from MessageDisplay

MessageDisplay::COLOR_MAP

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from MessageDisplay

#display_message, included, #message_display_prompt

Constructor Details

#initialize(repository_client:, state_store:, provider_name: nil, project_dir: Dir.pwd, label_config: {}, verbose: false, reviewers: nil, verifier: nil) ⇒ ReviewProcessor

Returns a new instance of ReviewProcessor.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/aidp/watch/review_processor.rb', line 28

def initialize(repository_client:, state_store:, provider_name: nil, project_dir: Dir.pwd, label_config: {}, verbose: false, reviewers: nil, verifier: nil)
  @repository_client = repository_client
  @state_store = state_store
  @state_extractor = GitHubStateExtractor.new(repository_client: repository_client)
  @provider_name = provider_name
  @project_dir = project_dir
  @verbose = verbose

  # Load label configuration
  @review_label = label_config[:review_trigger] || label_config["review_trigger"] || DEFAULT_REVIEW_LABEL

  # Initialize verifier (allow dependency injection for testing)
  @verifier = verifier || ImplementationVerifier.new(
    repository_client: repository_client,
    project_dir: project_dir
  )

  # Initialize reviewers (allow dependency injection for testing)
  @reviewers = reviewers || [
    Reviewers::SeniorDevReviewer.new(provider_name: provider_name),
    Reviewers::SecurityReviewer.new(provider_name: provider_name),
    Reviewers::PerformanceReviewer.new(provider_name: provider_name)
  ]
end

Instance Attribute Details

#review_labelObject (readonly)

Returns the value of attribute review_label.



26
27
28
# File 'lib/aidp/watch/review_processor.rb', line 26

def review_label
  @review_label
end

Instance Method Details

#process(pr) ⇒ Object



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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/aidp/watch/review_processor.rb', line 53

def process(pr)
  number = pr[:number]

  # Check if review already completed via GitHub comments
  if @state_extractor.review_completed?(pr)
    display_message("â„šī¸  Review for PR ##{number} already posted. Skipping.", type: :muted)
    return
  end

  display_message("🔍 Reviewing PR ##{number} (#{pr[:title]})", type: :info)

  # Fetch PR details
  pr_data = @repository_client.fetch_pull_request(number)
  files = @repository_client.fetch_pull_request_files(number)
  diff = @repository_client.fetch_pull_request_diff(number)

  # Check if PR is linked to an issue - if so, run implementation verification
  verification_result = check_implementation_completeness(pr_data)

  # Run reviews in parallel (conceptually - actual implementation is sequential)
  review_results = run_reviews(pr_data: pr_data, files: files, diff: diff)

  # Log review results
  log_review(number, review_results)

  # Format and post comment
  comment_body = format_review_comment(
    pr: pr_data,
    review_results: review_results,
    verification_result: verification_result
  )
  @repository_client.post_comment(number, comment_body)

  display_message("đŸ’Ŧ Posted review comment for PR ##{number}", type: :success)
  @state_store.record_review(number, {
    timestamp: Time.now.utc.iso8601,
    reviewers: review_results.map { |r| r[:persona] },
    total_findings: review_results.sum { |r| r[:findings].length }
  })

  # Remove review label after processing
  begin
    @repository_client.remove_labels(number, @review_label)
    display_message("đŸˇī¸  Removed '#{@review_label}' label after review", type: :info)
  rescue => e
    display_message("âš ī¸  Failed to remove review label: #{e.message}", type: :warn)
  end
rescue => e
  display_message("❌ Review failed: #{e.message}", type: :error)
  Aidp.log_error("review_processor", "Review failed", pr: number, error: e.message, backtrace: e.backtrace&.first(10))

  # Record failure state internally but DON'T post error to GitHub
  # (per issue #280 - error messages should never appear on issues)
  @state_store.record_review(number, {
    status: "error",
    error: e.message,
    error_class: e.class.name,
    timestamp: Time.now.utc.iso8601
  })
end