Class: Ocak::IssueFetcher

Inherits:
Object
  • Object
show all
Defined in:
lib/ocak/issue_fetcher.rb

Direct Known Subclasses

LocalIssueFetcher

Constant Summary collapse

LABEL_COLORS =
{
  'auto-ready' => '0E8A16',
  'auto-doing' => '1D76DB',
  'completed' => '6F42C1',
  'pipeline-failed' => 'D93F0B',
  'auto-reready' => 'FBCA04',
  'auto-pending-human' => 'F9D0C4'
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(config:, logger: nil) ⇒ IssueFetcher

Returns a new instance of IssueFetcher.



17
18
19
20
# File 'lib/ocak/issue_fetcher.rb', line 17

def initialize(config:, logger: nil)
  @config = config
  @logger = logger
end

Instance Method Details

#add_label(issue_number, label) ⇒ Object



41
42
43
# File 'lib/ocak/issue_fetcher.rb', line 41

def add_label(issue_number, label)
  run_gh('issue', 'edit', issue_number.to_s, '--add-label', label)
end

#comment(issue_number, body) ⇒ Object



54
55
56
# File 'lib/ocak/issue_fetcher.rb', line 54

def comment(issue_number, body)
  run_gh('issue', 'comment', issue_number.to_s, '--body', body)
end

#ensure_label(label) ⇒ Object



117
118
119
120
121
122
# File 'lib/ocak/issue_fetcher.rb', line 117

def ensure_label(label)
  color = LABEL_COLORS.fetch(label, 'ededed')
  run_gh('label', 'create', label, '--force', '--color', color) # --force: update if exists
rescue Errno::ENOENT => e
  @logger&.warn("Failed to create label '#{label}': #{e.message}")
end

#ensure_labels(labels) ⇒ Object



113
114
115
# File 'lib/ocak/issue_fetcher.rb', line 113

def ensure_labels(labels)
  labels.each { |label| ensure_label(label) }
end

#extract_issue_number_from_pr(pull_request) ⇒ Object



88
89
90
91
92
# File 'lib/ocak/issue_fetcher.rb', line 88

def extract_issue_number_from_pr(pull_request)
  body = pull_request['body'].to_s
  match = body.match(/(?:closes|fixes|resolves)\s+#(\d+)/i)
  match ? match[1].to_i : nil
end

#fetch_pr_comments(pr_number) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ocak/issue_fetcher.rb', line 74

def fetch_pr_comments(pr_number)
  stdout, _, status = run_gh(
    'pr', 'view', pr_number.to_s,
    '--json', 'comments,reviews'
  )
  return { comments: [], reviews: [] } unless status.success?

  data = JSON.parse(stdout)
  { comments: data.fetch('comments', []), reviews: data.fetch('reviews', []) }
rescue JSON::ParserError => e
  @logger&.warn("Failed to parse PR comments JSON: #{e.message}")
  { comments: [], reviews: [] }
end

#fetch_readyObject



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/ocak/issue_fetcher.rb', line 22

def fetch_ready
  stdout, _, status = run_gh(
    'issue', 'list',
    '--label', @config.label_ready,
    '--state', 'open',
    '--json', 'number,title,body,labels,author',
    '--limit', '50'
  )
  return [] unless status.success?

  issues = JSON.parse(stdout)
  issues.reject! { |i| in_progress?(i) }
  issues.select! { |i| authorized_issue?(i) }
  issues
rescue JSON::ParserError => e
  @logger&.warn("Failed to parse issue list JSON: #{e.message}")
  []
end

#fetch_reready_prsObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/ocak/issue_fetcher.rb', line 58

def fetch_reready_prs
  stdout, _, status = run_gh(
    'pr', 'list',
    '--label', @config.label_reready,
    '--state', 'open',
    '--json', 'number,title,body,headRefName,labels',
    '--limit', '20'
  )
  return [] unless status.success?

  JSON.parse(stdout)
rescue JSON::ParserError => e
  @logger&.warn("Failed to parse reready PRs JSON: #{e.message}")
  []
end

#pr_comment(pr_number, body) ⇒ Object



108
109
110
111
# File 'lib/ocak/issue_fetcher.rb', line 108

def pr_comment(pr_number, body)
  _, _, status = run_gh('pr', 'comment', pr_number.to_s, '--body', body)
  status.success?
end

#pr_transition(pr_number, remove_label: nil, add_label: nil) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ocak/issue_fetcher.rb', line 94

def pr_transition(pr_number, remove_label: nil, add_label: nil)
  if remove_label
    _, _, status = run_gh('pr', 'edit', pr_number.to_s, '--remove-label', remove_label)
    return false unless status.success?
  end

  if add_label
    _, _, status = run_gh('pr', 'edit', pr_number.to_s, '--add-label', add_label)
    return false unless status.success?
  end

  true
end

#remove_label(issue_number, label) ⇒ Object



45
46
47
# File 'lib/ocak/issue_fetcher.rb', line 45

def remove_label(issue_number, label)
  run_gh('issue', 'edit', issue_number.to_s, '--remove-label', label)
end

#transition(issue_number, from:, to:) ⇒ Object



49
50
51
52
# File 'lib/ocak/issue_fetcher.rb', line 49

def transition(issue_number, from:, to:)
  remove_label(issue_number, from) if from
  add_label(issue_number, to)
end

#view(issue_number, fields: 'number,title,body,labels') ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/ocak/issue_fetcher.rb', line 124

def view(issue_number, fields: 'number,title,body,labels')
  stdout, _, status = run_gh(
    'issue', 'view', issue_number.to_s,
    '--json', fields
  )
  return nil unless status.success?

  JSON.parse(stdout)
rescue JSON::ParserError => e
  @logger&.warn("Failed to parse issue view JSON: #{e.message}")
  nil
end