Skip to content
Open
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
2 changes: 2 additions & 0 deletions .github/workflows/pronto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ jobs:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Use specific rspec-its gem version (since we are using Ruby 2.5)
run: echo "gem 'rspec-its', '~> 1.3.0'" >> Gemfile.local
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/specs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,21 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
ruby: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4']
ruby: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4', '4.0']
exclude:
- ruby: "2.3" # Rugged uses the wrong openssl version on CI and segfaults (similar to https://github.com/libgit2/rugged/issues/718)
steps:
- uses: actions/checkout@v6
- name: Use specific gitlab gem version (if required)
if: matrix.ruby == '2.4'
run: echo "gem 'gitlab', '< 4.14.1'" >> Gemfile.local
- name: Use specific rspec-its gem version (if required)
if: matrix.ruby == '2.3' ||
matrix.ruby == '2.4' ||
matrix.ruby == '2.5' ||
matrix.ruby == '2.6' ||
matrix.ruby == '2.7'
run: echo "gem 'rspec-its', '~> 1.3.0'" >> Gemfile.local
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
Expand Down
23 changes: 16 additions & 7 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
AllCops:
TargetRubyVersion: 2.4
TargetRubyVersion: 2.5

Documentation:
Enabled: false

SignalException:
EnforcedStyle: only_raise
Metrics/AbcSize:
Max: 25

MultilineOperationIndentation:
EnforcedStyle: indented
Metrics/BlockLength:
Exclude:
- 'pronto.gemspec'
- 'spec/**/*'

Metrics/ModuleLength:
Exclude:
- 'spec/**/*'

MultilineMethodCallIndentation:
EnforcedStyle: indented

Metrics/AbcSize:
Max: 25
MultilineOperationIndentation:
EnforcedStyle: indented

SignalException:
EnforcedStyle: only_raise
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

source 'https://rubygems.org'

gemspec
Expand Down
9 changes: 6 additions & 3 deletions Rakefile
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#!/usr/bin/env rake
# frozen_string_literal: true

# !/usr/bin/env rake

require 'rubygems'
require 'bundler'
require 'bundler/gem_tasks'

begin
Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e
$stderr.puts e.message
$stderr.puts 'Run `bundle install` to install missing gems'
warn e.message
warn 'Run `bundle install` to install missing gems'
exit e.status_code
end

Expand Down
2 changes: 2 additions & 0 deletions bin/pronto
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

#!/usr/bin/env ruby

require 'pronto'
Expand Down
2 changes: 2 additions & 0 deletions lib/pronto.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

require 'rugged'
require 'octokit'
require 'gitlab'
Expand Down
28 changes: 13 additions & 15 deletions lib/pronto/bitbucket.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
# frozen_string_literal: true

module Pronto
class Bitbucket < Client
def pull_comments(sha)
@comment_cache["#{pull_id}/#{sha}"] ||= begin
client.pull_comments(slug, pull_id).map do |comment|
Comment.new(sha, comment.content, comment.filename, comment.line_to)
end
@comment_cache["#{pull_id}/#{sha}"] ||= client.pull_comments(slug, pull_id).map do |comment|
Comment.new(sha, comment.content, comment.filename, comment.line_to)
end
end

def commit_comments(sha)
@comment_cache[sha.to_s] ||= begin
client.commit_comments(slug, sha).map do |comment|
Comment.new(sha, comment.content, comment.filename, comment.line_to)
end
@comment_cache[sha.to_s] ||= client.commit_comments(slug, sha).map do |comment|
Comment.new(sha, comment.content, comment.filename, comment.line_to)
end
end

Expand All @@ -39,17 +37,17 @@ def approve_pull_request
def unapprove_pull_request
client.unapprove_pull_request(slug, pull_id)
end

private

def slug
return @config.bitbucket_slug if @config.bitbucket_slug
@slug ||= begin
@repo.remote_urls.map do |url|
hostname = Regexp.escape(@config.bitbucket_hostname)
match = %r{.*#{hostname}(:|\/)(?<slug>.*?)(?:\.git)?\z}.match(url)
match[:slug] if match
end.compact.first
end

@slug ||= @repo.remote_urls.map do |url|
hostname = Regexp.escape(@config.bitbucket_hostname)
match = %r{.*#{hostname}(:|/)(?<slug>.*?)(?:\.git)?\z}.match(url)
match[:slug] if match
end.compact.first
end

def client
Expand Down
18 changes: 9 additions & 9 deletions lib/pronto/bitbucket_server.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# frozen_string_literal: true

module Pronto
class BitbucketServer < Bitbucket
def pull_comments(sha)
@comment_cache["#{pull_id}/#{sha}"] ||= begin
client.pull_comments(slug, pull_id).map do |comment|
anchor = comment['commentAnchor']
if anchor
Comment.new(sha, comment['comment']['text'],
anchor['path'], anchor['line'])
end
end.compact
end
@comment_cache["#{pull_id}/#{sha}"] ||= client.pull_comments(slug, pull_id).map do |comment|
anchor = comment['commentAnchor']
if anchor
Comment.new(sha, comment['comment']['text'],
anchor['path'], anchor['line'])
end
end.compact
end

private
Expand Down
76 changes: 52 additions & 24 deletions lib/pronto/cli.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

require 'thor'

module Pronto
Expand All @@ -8,6 +10,7 @@ class CLI < Thor
class << self
def is_thor_reserved_word?(word, type)
return false if word == 'run'

super
end
end
Expand Down Expand Up @@ -50,33 +53,12 @@ def is_thor_reserved_word?(word, type)
desc: "Pick output formatters. Available: #{::Pronto::Formatter.names.join(', ')}"

def run(path = '.')
path = File.expand_path(path)

gem_names = options[:runner].any? ? options[:runner] : ::Pronto::GemNames.new.to_a
gem_names.each do |gem_name|
require "pronto/#{gem_name}"
end

formatters = ::Pronto::Formatter.get(options[:formatters])

commit_options = %i[workdir staged unstaged index]
commit = commit_options.find { |o| options[o] } || options[:commit]

repo_workdir = ::Rugged::Repository.discover(path).workdir
relative = path.sub(repo_workdir, '')

messages = Dir.chdir(repo_workdir) do
file = relative.length != path.length ? relative : nil
::Pronto.run(commit, '.', formatters, file)
end
if options[:'exit-code']
error_messages_count = messages.count { |m| m.level != :info }
exit(error_messages_count)
end
messages = execute_run(path)
handle_exit_code(messages) if options[:'exit-code']
rescue Rugged::RepositoryError
puts '"pronto" must be run from within a git repository or must be supplied the path to a git repository'
rescue Pronto::Error => e
$stderr.puts "Pronto errored: #{e.message}"
warn "Pronto errored: #{e.message}"
end

desc 'list', 'Lists pronto runners that are available to be used'
Expand All @@ -98,5 +80,51 @@ def version
def verbose_version
puts Version.verbose
end

private

def execute_run(path)
path = File.expand_path(path)
load_runners(runner_gem_names)
formatters = build_formatters
commit = resolve_commit
repo_workdir, relative = repo_and_relative(path)
collect_messages(repo_workdir, relative, commit, formatters, path)
end

def runner_gem_names
options[:runner].any? ? options[:runner] : ::Pronto::GemNames.new.to_a
end

def load_runners(gem_names)
gem_names.each { |gem_name| require "pronto/#{gem_name}" }
end

def build_formatters
::Pronto::Formatter.get(options[:formatters])
end

def resolve_commit
commit_options = %i[workdir staged unstaged index]
commit_options.find { |o| options[o] } || options[:commit]
end

def repo_and_relative(path)
repo_workdir = ::Rugged::Repository.discover(path).workdir
relative = path.sub(repo_workdir, '')
[repo_workdir, relative]
end

def collect_messages(repo_workdir, relative, commit, formatters, full_path)
Dir.chdir(repo_workdir) do
file = relative.length == full_path.length ? nil : relative
::Pronto.run(commit, '.', formatters, file)
end
end

def handle_exit_code(messages)
error_messages_count = messages.count { |m| m.level != :info }
exit(error_messages_count)
end
end
end
10 changes: 6 additions & 4 deletions lib/pronto/client.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

module Pronto
class Client
def initialize(repo)
Expand All @@ -8,12 +10,12 @@ def initialize(repo)
end

def env_pull_id
if (pull_request = ENV['PULL_REQUEST_ID'])
warn "[DEPRECATION] `PULL_REQUEST_ID` is deprecated. Please use `PRONTO_PULL_REQUEST_ID` instead."
if (pull_request = ENV.fetch('PULL_REQUEST_ID', nil))
warn '[DEPRECATION] `PULL_REQUEST_ID` is deprecated. Please use `PRONTO_PULL_REQUEST_ID` instead.'
end

pull_request ||= ENV['PRONTO_PULL_REQUEST_ID']
pull_request.to_i if pull_request
pull_request ||= ENV.fetch('PRONTO_PULL_REQUEST_ID', nil)
pull_request&.to_i
end
end
end
7 changes: 4 additions & 3 deletions lib/pronto/clients/bitbucket_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

class BitbucketClient
include HTTParty

base_uri 'https://api.bitbucket.org/2.0/repositories'

def initialize(username, password)
Expand All @@ -13,7 +14,7 @@ def initialize(username, password)
def commit_comments(slug, sha)
response = get("/#{slug}/commit/#{sha}/comments?pagelen=100")
result = parse_comments(openstruct(response))
while (response['next'])
while response['next']
response = get response['next']
result.concat(parse_comments(openstruct(response)))
end
Expand All @@ -28,7 +29,7 @@ def pull_comments(slug, pull_id)
response = get("/#{slug}/pullrequests/#{pull_id}/comments?pagelen=100")
parse_comments(openstruct(response))
result = parse_comments(openstruct(response))
while (response['next'])
while response['next']
response = get response['next']
result.concat(parse_comments(openstruct(response)))
end
Expand Down Expand Up @@ -71,7 +72,7 @@ def parse_comments(values)
end
values
end

def post(url, body, path, position)
options = {
body: {
Expand Down
2 changes: 2 additions & 0 deletions lib/pronto/comment.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

module Pronto
Comment = Struct.new(:sha, :body, :path, :position) do
def ==(other)
Expand Down
16 changes: 7 additions & 9 deletions lib/pronto/config.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
# frozen_string_literal: true

module Pronto
class Config
def initialize(config_hash = ConfigFile.new.to_h)
@config_hash = config_hash
end

%w[github gitlab bitbucket].each do |service|
ConfigFile::EMPTY[service].each do |key, _|
ConfigFile::EMPTY[service].each_key do |key|
name = "#{service}_#{key}"
define_method(name) { ENV["PRONTO_#{name.upcase}"] || @config_hash[service][key] }
end
end

def default_commit
default_commit =
ENV['PRONTO_DEFAULT_COMMIT'] ||
ENV['PRONTO_DEFAULT_COMMIT'] ||
@config_hash.fetch('default_commit', 'master')
default_commit
end

def consolidate_comments?
consolidated =
ENV['PRONTO_CONSOLIDATE_COMMENTS'] ||
ENV['PRONTO_CONSOLIDATE_COMMENTS'] ||
@config_hash.fetch('consolidate_comments', false)
consolidated
end

def github_review_type
Expand Down Expand Up @@ -68,7 +66,7 @@ def max_warnings

def message_format(formatter)
formatter_config = @config_hash[formatter]
if formatter_config && formatter_config.key?('format')
if formatter_config&.key?('format')
formatter_config['format']
else
fetch_value('format')
Expand All @@ -95,7 +93,7 @@ def logger
def fetch_integer(key)
full_key = env_key(key)

(ENV[full_key] && Integer(ENV[full_key])) || @config_hash[key]
(ENV.fetch(full_key, nil) && Integer(ENV.fetch(full_key, nil))) || @config_hash[key]
end

def fetch_value(key)
Expand Down
Loading