2323
2424# Script
2525
26- require "json"
27- require "net/http"
28-
29- module Github
30- HttpError = Class . new ( StandardError )
31-
32- CONNECTION = Net ::HTTP . new ( "api.github.com" , 443 ) . tap { |http | http . use_ssl = true }
33- REQUEST_METHOD_TO_CLASS = {
34- get : Net ::HTTP ::Get ,
35- patch : Net ::HTTP ::Patch ,
36- post : Net ::HTTP ::Post ,
37- delete : Net ::HTTP ::Delete ,
38- } . freeze
39-
40- REQUEST_METHOD_TO_CLASS . each do |method , klass |
41- define_singleton_method ( method ) do |path , params = nil |
42- request ( klass , path , params )
43- end
44-
45- define_singleton_method ( "#{ method } !" ) do |path , params = nil |
46- response = request ( klass , path , params )
47- raise HttpError , "status: #{ response . code } , body: #{ response . body } " unless response . is_a? ( Net ::HTTPSuccess )
48-
49- JSON . parse ( response . body ) if response . body
50- end
51- end
52-
53- def self . request ( request_class , path , params = nil )
54- request = request_class . new ( path )
55- request . content_type = "application/json"
56- request . body = params &.to_json
57- request [ "Authorization" ] = "Bearer #{ ENV . fetch ( 'GITHUB_TOKEN' ) } "
58- request [ "Accept" ] = "application/vnd.github.v3+json"
59-
60- CONNECTION . request ( request )
61- end
62- end
26+ require_relative "lib/github"
6327
6428# Figure out which ruby files have changed and run Rubocop on them
6529
6630github_event = JSON . parse ( File . read ( ENV . fetch ( "GITHUB_EVENT_PATH" ) ) )
6731pr_number = github_event . fetch ( "pull_request" ) . fetch ( "number" )
6832owner_and_repository = ENV . fetch ( "GITHUB_REPOSITORY" )
6933
70- changed_files = [ ]
71- 1 . step do |page |
72- files = Github . get! ( "/repos/#{ owner_and_repository } /pulls/#{ pr_number } /files?per_page=100&page=#{ page } " )
73- changed_files . concat ( files )
74- break if files . length < 100
75- end
76- changed_ruby_files = changed_files
77- . reject { |file | file . fetch ( "status" ) == "removed" }
78- . select { |file | file . fetch ( "filename" ) . end_with? ( ".rb" ) }
79- . map { |file | file . fetch ( "filename" ) }
34+ changed_ruby_files = Github . pull_request_ruby_files ( owner_and_repository , pr_number )
8035
8136# JSON reference: https://docs.rubocop.org/rubocop/formatters.html#json-formatter
8237files_with_offenses =
8338 if changed_ruby_files . any?
84- command = "rubocop #{ changed_ruby_files . join ( ' ' ) } --format json --force-exclusion"
39+ command = "rubocop #{ changed_ruby_files . map ( & :path ) . join ( ' ' ) } --format json --force-exclusion"
8540
8641 puts "Running rubocop with: #{ command } "
87- rubocop_output = `#{ command } `
88-
89- JSON . parse ( rubocop_output ) . fetch ( "files" )
42+ JSON . parse ( `#{ command } ` ) . fetch ( "files" )
9043 else
9144 puts "No changed Ruby files, skipping rubocop"
9245
@@ -126,6 +79,11 @@ def self.request(request_class, path, params = nil)
12679
12780# Comment on the pull request with the offenses found
12881
82+ def in_diff? ( changed_files , path , line )
83+ file = changed_files . find { |changed_file | changed_file . path == path }
84+ file &.changed_lines &.include? ( line )
85+ end
86+
12987offences_outside_diff = [ ]
13088
13189files_with_offenses . each do |file |
@@ -166,26 +124,21 @@ def self.request(request_class, path, params = nil)
166124
167125 puts "Updating comment #{ comment_id } on #{ path } line #{ line } "
168126 Github . patch ( "/repos/#{ owner_and_repository } /pulls/comments/#{ comment_id } " , body : body )
169- else
127+ elsif in_diff? ( changed_ruby_files , path , line )
170128 puts "Commenting on #{ path } line #{ line } "
171129
172130 # Somehow the commit_id should not be just the HEAD SHA: https://stackoverflow.com/a/71431370/1075108
173131 commit_id = github_event . fetch ( "pull_request" ) . fetch ( "head" ) . fetch ( "sha" )
174132
175- response = Github . post (
133+ Github . post! (
176134 "/repos/#{ owner_and_repository } /pulls/#{ pr_number } /comments" ,
177135 body : body ,
178136 path : path ,
179137 commit_id : commit_id ,
180138 line : line ,
181139 )
182-
183- # Rubocop might hit errors on lines which are not part of the diff and thus cannot be commented on.
184- if response . code == "422" && response . body . include? ( "line must be part of the diff" )
185- puts "Deferring comment on #{ path } line #{ line } because it isn't part of the diff"
186-
187- offences_outside_diff << { path : path , line : line , message : message }
188- end
140+ else
141+ offences_outside_diff << { path : path , line : line , message : message }
189142 end
190143 end
191144end
@@ -196,7 +149,9 @@ def self.request(request_class, path, params = nil)
196149existing_separate_comment = separate_comments . find do |comment |
197150 comment . fetch ( "body" ) . include? ( "rubocop-comment-id: outside-diff" )
198151end
152+
199153if offences_outside_diff . any?
154+ puts "Found #{ offences_outside_diff . count } offenses outside of the diff"
200155
201156 body = <<~BODY
202157 <!-- rubocop-comment-id: outside-diff -->
@@ -215,8 +170,8 @@ def self.request(request_class, path, params = nil)
215170 if existing_separate_comment . fetch ( "body" ) == body
216171 puts "Skipping unchanged separate comment #{ existing_comment_id } "
217172 else
218- puts "Updating comment #{ existing_comment_id } on pull request "
219- Github . patch! ( "/repos/#{ owner_and_repository } /pulls /comments/#{ existing_comment_id } " , body : body )
173+ puts "Updating separate comment #{ existing_comment_id } "
174+ Github . patch! ( "/repos/#{ owner_and_repository } /issues /comments/#{ existing_comment_id } " , body : body )
220175 end
221176 else
222177 puts "Commenting on pull request with offenses found outside the diff"
@@ -227,6 +182,8 @@ def self.request(request_class, path, params = nil)
227182 existing_comment_id = existing_separate_comment . fetch ( "id" )
228183 puts "Deleting resolved separate comment #{ existing_comment_id } "
229184 Github . delete ( "/repos/#{ owner_and_repository } /issues/comments/#{ existing_comment_id } " )
185+ else
186+ puts "No offenses found outside of the diff and no existing separate comment to remove"
230187end
231188
232189# Fail the build if there were any offenses
0 commit comments