From 7078d51cecc58092ac1c60ce01c27bec5bc4972f Mon Sep 17 00:00:00 2001 From: Artem Yegorov Date: Tue, 27 Aug 2024 23:06:34 +0300 Subject: [PATCH] #190: calculate average review time for pr --- .../quality-of-service/quality-of-service.rb | 12 ++ judges/quality-of-service/simple-collect.yml | 1 + test/judges/test-quality-of-service.rb | 157 ++++++++++++++++++ 3 files changed, 170 insertions(+) diff --git a/judges/quality-of-service/quality-of-service.rb b/judges/quality-of-service/quality-of-service.rb index deeeb4a3..5efcd555 100644 --- a/judges/quality-of-service/quality-of-service.rb +++ b/judges/quality-of-service/quality-of-service.rb @@ -111,4 +111,16 @@ end f.average_pull_hoc_size = hocs.empty? ? 0 : hocs.sum.to_f / hocs.size f.average_pull_files_size = files.empty? ? 0 : files.sum.to_f / files.size + + # Average review time + review_times = [] + Fbe.unmask_repos.each do |repo| + Fbe.octo.search_issues( + "repo:#{repo} type:pr created:>#{f.since.utc.iso8601[0..9]}" + )[:items].each do |pr| + review = Fbe.octo.pull_request_reviews(repo, pr[:number]).min_by { |r| r[:submitted_at] } + review_times << (review[:submitted_at] - pr[:created_at]).to_i if review + end + end + f.average_review_time = review_times.empty? ? 0 : review_times.sum.to_f / review_times.size end diff --git a/judges/quality-of-service/simple-collect.yml b/judges/quality-of-service/simple-collect.yml index a46c38aa..1bfc01ea 100644 --- a/judges/quality-of-service/simple-collect.yml +++ b/judges/quality-of-service/simple-collect.yml @@ -48,3 +48,4 @@ expected: - /fb/f[average_pull_rejection_rate != 0] - /fb/f[average_pull_hoc_size != 0] - /fb/f[average_pull_files_size != 0] + - /fb/f[average_review_time != 0] diff --git a/test/judges/test-quality-of-service.rb b/test/judges/test-quality-of-service.rb index 235de431..62171cd9 100644 --- a/test/judges/test-quality-of-service.rb +++ b/test/judges/test-quality-of-service.rb @@ -124,6 +124,28 @@ def test_runs_when_run_duration_ms_is_nil 'https://api.github.com/repos/foo/foo/pulls/12', body: { id: 50, number: 12, additions: 12, deletions: 5, changed_files: 3 } ) + stub_github( + 'https://api.github.com/search/issues?per_page=100&q=repo:foo/foo%20type:pr%20created:%3E2024-08-02', + body: { + total_count: 1, incomplete_results: false, + items: [{ id: 50, number: 12, title: 'Awesome 12', created_at: Time.parse('2024-08-20 22:00:00 UTC') }] + } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/12/reviews?per_page=100', + body: [{ id: 22_449_326, submitted_at: Time.parse('2024-08-21 22:00:00 UTC') }] + ) + stub_github( + 'https://api.github.com/search/issues?per_page=100&q=repo:foo/foo%20type:pr%20created:%3E2024-07-15', + body: { + total_count: 1, incomplete_results: false, + items: [{ id: 50, number: 12, title: 'Awesome 12', created_at: Time.parse('2024-07-20 22:00:00 UTC') }] + } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/12/reviews?per_page=100', + body: [{ id: 22_449_326, submitted_at: Time.parse('2024-07-21 22:00:00 UTC') }] + ) fb = Factbase.new Time.stub(:now, Time.parse('2024-08-12 21:00:00 UTC')) do load_it('quality-of-service', fb) @@ -295,6 +317,27 @@ def test_quality_of_service_average_issues 'https://api.github.com/repos/foo/foo/pulls/12', body: { id: 50, number: 12, additions: 12, deletions: 5, changed_files: 3 } ) + stub_github( + 'https://api.github.com/search/issues?per_page=100&q=repo:foo/foo%20type:pr%20created:%3E2024-08-02', + body: { + total_count: 1, incomplete_results: false, + items: [{ id: 50, number: 12, title: 'Awesome 12', created_at: Time.parse('2024-08-20 22:00:00 UTC') }] + } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/12/reviews?per_page=100', + body: [ + { + id: 22_449_326, + user: { login: 'yegor256', id: 526_301, type: 'User' }, + body: 'Some text 1', + state: 'CHANGES_REQUESTED', + author_association: 'CONTRIBUTOR', + submitted_at: Time.parse('2024-08-21 22:00:00 UTC'), + commit_id: 'a15c2893f1b5453' + } + ] + ) fb = Factbase.new f = fb.insert f.what = 'pmp' @@ -412,6 +455,17 @@ def test_quality_of_service_average_hocs_and_files changed_files: 4 } ) + stub_github( + 'https://api.github.com/search/issues?per_page=100&q=repo:foo/foo%20type:pr%20created:%3E2024-08-02', + body: { + total_count: 1, incomplete_results: false, + items: [{ id: 50, number: 12, title: 'Awesome 12', created_at: Time.parse('2024-08-20 22:00:00 UTC') }] + } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/12/reviews?per_page=100', + body: [{ id: 22_449_326, submitted_at: Time.parse('2024-08-21 22:00:00 UTC') }] + ) fb = Factbase.new f = fb.insert f.what = 'pmp' @@ -427,4 +481,107 @@ def test_quality_of_service_average_hocs_and_files assert_in_delta(2.8, f.average_pull_files_size) end end + + def test_quality_of_service_average_review_time + WebMock.disable_net_connect! + stub_github('https://api.github.com/repos/foo/foo', body: { id: 42, full_name: 'foo/foo' }) + stub_github( + 'https://api.github.com/repos/foo/foo/actions/runs?created=%3E2024-08-02&per_page=100', + body: { total_count: 0, workflow_runs: [] } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/releases?per_page=100', + body: [] + ) + stub_github( + 'https://api.github.com/search/issues?per_page=100&q=repo:foo/foo%20type:issue%20closed:%3E2024-08-02', + body: { + total_count: 1, incomplete_results: false, items: [{ number: 42, labels: [{ name: 'bug' }] }] + } + ) + stub_github( + 'https://api.github.com/search/issues?per_page=100&q=repo:foo/foo%20type:pr%20closed:%3E2024-08-02', + body: { + total_count: 2, incomplete_results: false, + items: [{ id: 42, number: 10, title: 'Awesome 10' }, { id: 43, number: 11, title: 'Awesome 11' }] + } + ) + (Date.parse('2024-08-02')..Date.parse('2024-08-09')).each do |date| + stub_github( + 'https://api.github.com/search/issues?per_page=100&' \ + "q=repo:foo/foo%20type:issue%20created:2024-08-02..#{date}", + body: { total_count: 0, items: [] } + ) + end + stub_github( + 'https://api.github.com/search/issues?per_page=100&' \ + 'q=repo:foo/foo%20type:pr%20is:unmerged%20closed:%3E2024-08-02', + body: { + total_count: 1, incomplete_results: false, items: [{ id: 42, number: 10, title: 'Awesome 10' }] + } + ) + stub_github( + 'https://api.github.com/search/issues?per_page=100&' \ + 'q=repo:foo/foo%20type:pr%20is:merged%20closed:%3E2024-08-02', + body: { + total_count: 1, incomplete_results: false, items: [{ id: 50, number: 12, title: 'Awesome 12' }] + } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/12', + body: { id: 50, number: 12, additions: 10, deletions: 5, changed_files: 1 } + ) + stub_github( + 'https://api.github.com/search/issues?per_page=100&q=repo:foo/foo%20type:pr%20created:%3E2024-08-02', + body: { + total_count: 1, incomplete_results: false, + items: [ + { id: 50, number: 12, title: 'Awesome 12', created_at: Time.parse('2024-08-20 22:00:00 UTC') }, + { id: 51, number: 14, title: 'Awesome 14', created_at: Time.parse('2024-08-23 12:00:00 UTC') }, + { id: 52, number: 16, title: 'Awesome 16', created_at: Time.parse('2024-08-25 12:00:00 UTC') } + ] + } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/12/reviews?per_page=100', + body: [ + { + id: 22_449_328, body: 'Some text 3', state: 'CHANGES_REQUESTED', + author_association: 'CONTRIBUTOR', submitted_at: Time.parse('2024-08-23 10:00:00 UTC') + }, + { + id: 22_449_327, body: 'Some text 2', state: 'CHANGES_REQUESTED', + author_association: 'CONTRIBUTOR', submitted_at: Time.parse('2024-08-22 10:00:00 UTC') + }, + { + id: 22_449_326, body: 'Some text 1', state: 'CHANGES_REQUESTED', + author_association: 'CONTRIBUTOR', submitted_at: Time.parse('2024-08-21 22:00:00 UTC') + } + ] + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/14/reviews?per_page=100', + body: [ + { + id: 22_449_329, body: 'Some text 1', state: 'CHANGES_REQUESTED', + author_association: 'CONTRIBUTOR', submitted_at: Time.parse('2024-08-23 15:30:00 UTC') + } + ] + ) + stub_github('https://api.github.com/repos/foo/foo/pulls/16/reviews?per_page=100', body: []) + + fb = Factbase.new + f = fb.insert + f.what = 'pmp' + f.area = 'quality' + f.qos_days = 7 + f.qos_interval = 3 + Time.stub(:now, Time.parse('2024-08-09 21:00:00 UTC')) do + load_it('quality-of-service', fb) + f = fb.query('(eq what "quality-of-service")').each.to_a.first + assert_equal(Time.parse('2024-08-02 21:00:00 UTC'), f.since) + assert_equal(Time.parse('2024-08-09 21:00:00 UTC'), f.when) + assert_in_delta(49_500, f.average_review_time) + end + end end