Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/auto_review_pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Auto Review PR
on:
pull_request_target:
types: [opened, ready_for_review, reopened]
branches: [master]

permissions:
contents: read

jobs:
auto-review-pr:
name: Auto Review PR
runs-on: ubuntu-latest
if: ${{ github.repository == 'ruby/ruby' && github.base_ref == 'master' }}

permissions:
pull-requests: write
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v4

- uses: ruby/setup-ruby@ab177d40ee5483edb974554986f56b33477e21d0 # v1.265.0
with:
ruby-version: '3.4'
bundler: none

- name: Auto Review PR
run: ruby tool/auto_review_pr.rb "$GITHUB_PR_NUMBER"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
2 changes: 1 addition & 1 deletion .github/workflows/sync_default_gems.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:

- name: Push
run: |
git pull --ff-only origin ${GITHUB_REF#refs/heads/}
git pull --rebase origin ${GITHUB_REF#refs/heads/}
git push origin ${GITHUB_REF#refs/heads/}
if: ${{ steps.sync.outputs.update }}

Expand Down
11 changes: 8 additions & 3 deletions common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -624,15 +624,20 @@ html: PHONY main srcs-doc
@echo Generating RDoc HTML files
$(Q) $(RDOC) --op "$(HTMLOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) .

RDOC_COVERAGE_EXCLUDES = -x ^ext/json -x ^ext/openssl -x ^ext/psych \
-x ^lib/bundler -x ^lib/rubygems \
-x ^lib/did_you_mean -x ^lib/error_highlight -x ^lib/syntax_suggest

rdoc-coverage: PHONY main srcs-doc
@echo Generating RDoc coverage report
$(Q) $(RDOC) --quiet -C $(RDOCFLAGS) .
$(Q) $(RDOC) --quiet -C $(RDOCFLAGS) $(RDOC_COVERAGE_EXCLUDES) .

undocumented: PHONY main srcs-doc
$(Q) $(RDOC) --quiet -C $(RDOCFLAGS) . | \
$(Q) $(RDOC) --quiet -C $(RDOCFLAGS) $(RDOC_COVERAGE_EXCLUDES) . | \
sed -n \
-e '/^ *# in file /{' -e 's///;N;s/\n/: /p' -e '}' \
-e 's/^ *\(.*[^ ]\) *# in file \(.*\)/\2: \1/p' | sort
-e 's/^ *\(.*[^ ]\) *# in file \(.*\)/\2: \1/p' | \
sort -t: -k1,1 -k2n,2

RDOCBENCHOUT=/tmp/rdocbench

Expand Down
5 changes: 5 additions & 0 deletions ext/coverage/lib/coverage.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
require "coverage.so"

module Coverage
# call-seq:
# line_stub(file) -> array
#
# A simple helper function that creates the "stub" of line coverage
# from a given source code.
def self.line_stub(file)
lines = File.foreach(file).map { nil }
iseqs = [RubyVM::InstructionSequence.compile_file(file)]
Expand Down
7 changes: 7 additions & 0 deletions ext/objspace/object_tracing.c
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,13 @@ object_allocations_reporter(FILE *out, void *ptr)
fprintf(out, "== object_allocations_reporter: END\n");
}

/*
* call-seq: trace_object_allocations_debug_start
*
* Starts tracing object allocations for GC debugging.
* If you encounter the BUG "... is T_NONE" (and so on) on your
* application, please try this method at the beginning of your app.
*/
static VALUE
trace_object_allocations_debug_start(VALUE self)
{
Expand Down
20 changes: 12 additions & 8 deletions gc/mmtk/mmtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1022,16 +1022,20 @@ rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr)
gc_run_finalizers(objspace);
}

struct MMTk_RawVecOfObjRef registered_candidates = mmtk_get_all_obj_free_candidates();
for (size_t i = 0; i < registered_candidates.len; i++) {
VALUE obj = (VALUE)registered_candidates.ptr[i];

if (rb_gc_shutdown_call_finalizer_p(obj)) {
rb_gc_obj_free(objspace_ptr, obj);
RBASIC(obj)->flags = 0;
unsigned int lev = RB_GC_VM_LOCK();
{
struct MMTk_RawVecOfObjRef registered_candidates = mmtk_get_all_obj_free_candidates();
for (size_t i = 0; i < registered_candidates.len; i++) {
VALUE obj = (VALUE)registered_candidates.ptr[i];

if (rb_gc_shutdown_call_finalizer_p(obj)) {
rb_gc_obj_free(objspace_ptr, obj);
RBASIC(obj)->flags = 0;
}
}
mmtk_free_raw_vec_of_obj_ref(registered_candidates);
}
mmtk_free_raw_vec_of_obj_ref(registered_candidates);
RB_GC_VM_UNLOCK(lev);

gc_run_finalizers(objspace);
}
Expand Down
3 changes: 3 additions & 0 deletions lib/net/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1825,6 +1825,8 @@ def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_use_ss
}
end

# :startdoc:

class << HTTP
# Returns true if self is a class which was created by HTTP::Proxy.
def proxy_class?
Expand Down Expand Up @@ -1948,6 +1950,7 @@ def edit_path(path)
path
end
end
# :startdoc:

#
# HTTP operations
Expand Down
104 changes: 104 additions & 0 deletions tool/auto_review_pr.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require 'json'
require 'net/http'
require 'uri'
require_relative './sync_default_gems'

class GitHubAPIClient
def initialize(token)
@token = token
end

def get(path)
response = Net::HTTP.get_response(URI("https://api.github.com#{path}"), {
'Authorization' => "token #{@token}",
'Accept' => 'application/vnd.github.v3+json',
}).tap(&:value)
JSON.parse(response.body, symbolize_names: true)
end

def post(path, body = {})
body = JSON.dump(body)
response = Net::HTTP.post(URI("https://api.github.com#{path}"), body, {
'Authorization' => "token #{@token}",
'Accept' => 'application/vnd.github.v3+json',
'Content-Type' => 'application/json',
}).tap(&:value)
JSON.parse(response.body, symbolize_names: true)
end
end

class AutoReviewPR
REPO = 'ruby/ruby'

COMMENT_USER = 'github-actions[bot]'
COMMENT_PREFIX = 'The following files are maintained in the following upstream repositories:'
COMMENT_SUFFIX = 'Please file a pull request to the above instead. Thank you!'

def initialize(client)
@client = client
end

def review(pr_number)
# Fetch the list of files changed by the PR
changed_files = @client.get("/repos/#{REPO}/pulls/#{pr_number}/files").map { it.fetch(:filename) }

# Build a Hash: { upstream_repo => files, ... }
upstream_repos = changed_files.group_by { |file| find_upstream_repo(file) }
upstream_repos.delete(nil) # exclude no-upstream files
upstream_repos.delete('prism') if changed_files.include?('prism_compile.c') # allow prism changes in this case
if upstream_repos.empty?
puts "Skipped: The PR ##{pr_number} doesn't have upstream repositories."
return
end

# Check if the PR is already reviewed
existing_comments = @client.get("/repos/#{REPO}/issues/#{pr_number}/comments")
existing_comments.map! { [it.fetch(:user).fetch(:login), it.fetch(:body)] }
if existing_comments.any? { |user, comment| user == COMMENT_USER && comment.start_with?(COMMENT_PREFIX) }
puts "Skipped: The PR ##{pr_number} already has an automated review comment."
return
end

# Post a comment
comment = format_comment(upstream_repos)
result = @client.post("/repos/#{REPO}/issues/#{pr_number}/comments", { body: comment })
puts "Success: #{JSON.pretty_generate(result)}"
end

private

def find_upstream_repo(file)
SyncDefaultGems::REPOSITORIES.each do |repo_name, repository|
repository.mappings.each do |_src, dst|
if file.start_with?(dst)
return repo_name
end
end
end
nil
end

# upstream_repos: { upstream_repo => files, ... }
def format_comment(upstream_repos)
comment = +''
comment << "#{COMMENT_PREFIX}\n\n"

upstream_repos.each do |upstream_repo, files|
comment << "* https://github.com/ruby/#{upstream_repo}\n"
files.each do |file|
comment << " * #{file}\n"
end
end

comment << "\n#{COMMENT_SUFFIX}"
comment
end
end

pr_number = ARGV[0] || abort("Usage: #{$0} <pr_number>")
client = GitHubAPIClient.new(ENV.fetch('GITHUB_TOKEN'))

AutoReviewPR.new(client).review(pr_number)
1 change: 1 addition & 0 deletions tool/sync_default_gems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def lib((upstream, branch), gemspec_in_subdir: false)
])
end

# Note: tool/auto_review_pr.rb also depends on this constant.
REPOSITORIES = {
"io-console": repo("ruby/io-console", [
["ext/io/console", "ext/io/console"],
Expand Down