diff --git a/judges/quality-of-service/quality-of-service.rb b/judges/quality-of-service/quality-of-service.rb index 14df2304b..deeeb4a37 100644 --- a/judges/quality-of-service/quality-of-service.rb +++ b/judges/quality-of-service/quality-of-service.rb @@ -95,4 +95,20 @@ )[:total_count] end f.average_pull_rejection_rate = pulls.zero? ? 0 : rejected.to_f / pulls + + # Average HOC and number of files changed in recent merged PRs + hocs = [] + files = [] + Fbe.unmask_repos.each do |repo| + Fbe.octo.search_issues( + "repo:#{repo} type:pr is:merged closed:>#{f.since.utc.iso8601[0..9]}" + )[:items].each do |json| + Fbe.octo.pull_request(repo, json[:number]).then do |pull| + hocs << (pull[:additions] + pull[:deletions]) + files << pull[:changed_files] + end + end + 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 end diff --git a/judges/quality-of-service/simple-collect.yml b/judges/quality-of-service/simple-collect.yml index ad97bcea4..a46c38aa3 100644 --- a/judges/quality-of-service/simple-collect.yml +++ b/judges/quality-of-service/simple-collect.yml @@ -46,3 +46,5 @@ expected: - /fb/f[average_build_duration != 0] - /fb/f[average_backlog_size != 0] - /fb/f[average_pull_rejection_rate != 0] + - /fb/f[average_pull_hoc_size != 0] + - /fb/f[average_pull_files_size != 0] diff --git a/test/judges/test-quality-of-service.rb b/test/judges/test-quality-of-service.rb index 9b64f53ba..235de431b 100644 --- a/test/judges/test-quality-of-service.rb +++ b/test/judges/test-quality-of-service.rb @@ -113,6 +113,17 @@ def test_runs_when_run_duration_ms_is_nil 'content-type': 'application/json' } ) + stub_github( + 'https://api.github.com/search/issues?per_page=100&' \ + 'q=repo:foo/foo%20type:pr%20is:merged%20closed:%3E2024-07-15', + 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: 12, deletions: 5, changed_files: 3 } + ) fb = Factbase.new Time.stub(:now, Time.parse('2024-08-12 21:00:00 UTC')) do load_it('quality-of-service', fb) @@ -272,6 +283,18 @@ def test_quality_of_service_average_issues 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: 12, deletions: 5, changed_files: 3 } + ) fb = Factbase.new f = fb.insert f.what = 'pmp' @@ -286,4 +309,122 @@ def test_quality_of_service_average_issues assert_in_delta(2.125, f.average_backlog_size) end end + + def test_quality_of_service_average_hocs_and_files + 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' }, + { id: 52, number: 14, title: 'Awesome 14' }, + { id: 54, number: 16, title: 'Awesome 16' }, + { id: 56, number: 18, title: 'Awesome 18' }, + { id: 58, number: 20, title: 'Awesome 20' } + ] + } + ) + 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/repos/foo/foo/pulls/14', + body: { + id: 52, + number: 14, + additions: 0, + deletions: 3, + changed_files: 2 + } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/16', + body: { + id: 54, + number: 16, + additions: 8, + deletions: 9, + changed_files: 3 + } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/18', + body: { + id: 56, + number: 18, + additions: 30, + deletions: 7, + changed_files: 4 + } + ) + stub_github( + 'https://api.github.com/repos/foo/foo/pulls/20', + body: { + id: 58, + number: 20, + additions: 20, + deletions: 0, + changed_files: 4 + } + ) + 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(18.4, f.average_pull_hoc_size) + assert_in_delta(2.8, f.average_pull_files_size) + end + end end