Skip to content

Commit

Permalink
Add BitBucket support
Browse files Browse the repository at this point in the history
  • Loading branch information
nicka committed Mar 25, 2016
1 parent 8d79b5c commit 200a660
Show file tree
Hide file tree
Showing 13 changed files with 389 additions and 2 deletions.
6 changes: 6 additions & 0 deletions lib/pronto.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
require 'octokit'
require 'gitlab'
require 'forwardable'
require 'httparty'

require 'pronto/gem_names'

require 'pronto/logger'
require 'pronto/config_file'
require 'pronto/config'

require 'pronto/clients/bitbucket_client'

require 'pronto/git/repository'
require 'pronto/git/patches'
require 'pronto/git/patch'
Expand All @@ -20,12 +23,15 @@
require 'pronto/runners'
require 'pronto/github'
require 'pronto/gitlab'
require 'pronto/bitbucket'

require 'pronto/formatter/text_formatter'
require 'pronto/formatter/json_formatter'
require 'pronto/formatter/github_formatter'
require 'pronto/formatter/github_pull_request_formatter'
require 'pronto/formatter/gitlab_formatter'
require 'pronto/formatter/bitbucket_formatter'
require 'pronto/formatter/bitbucket_pull_request_formatter'
require 'pronto/formatter/checkstyle_formatter'
require 'pronto/formatter/null_formatter'
require 'pronto/formatter/formatter'
Expand Down
93 changes: 93 additions & 0 deletions lib/pronto/bitbucket.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
module Pronto
class Bitbucket
def initialize(repo)
@repo = repo
@config = Config.new
@comment_cache = {}
@pull_id_cache = {}
end

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
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
end
end

def create_commit_comment(comment)
@config.logger.log("Creating commit comment on #{comment.sha}")
client.create_commit_comment(slug, comment.sha, comment.body,
comment.path, comment.position)
end

def create_pull_comment(comment)
@config.logger.log("Creating pull request comment on #{pull_id}")
client.create_pull_comment(slug, pull_id, comment.body,
pull_sha || comment.sha,
comment.path, comment.position)
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 = /.*#{hostname}(:|\/)(?<slug>.*?)(?:\.git)?\z/.match(url)
match[:slug] if match
end.compact.first
end
end

def client
@client ||= BitbucketClient.new(@config.bitbucket_username,
@config.bitbucket_password)
end

def pull_id
pull ? pull.id.to_i : env_pull_id.to_i
end

def env_pull_id
ENV['PULL_REQUEST_ID']
end

def pull_sha
pull.source['commit']['hash'] if pull
end

def pull
@pull ||= if env_pull_id
pull_requests.find { |pr| pr.id.to_i == env_pull_id.to_i }
elsif @repo.branch
pull_requests.find { |pr| pr.branch['name'] == @repo.branch }
end
end

def pull_requests
@pull_requests ||= client.pull_requests(slug)
end

Comment = Struct.new(:sha, :body, :path, :position) do
def ==(other)
position == other.position &&
path == other.path &&
body == other.body
end

def to_s
"[#{sha}] #{path}:#{position} - #{body}"
end
end
end
end
51 changes: 51 additions & 0 deletions lib/pronto/clients/bitbucket_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
class BitbucketClient
include HTTParty
base_uri "https://api.bitbucket.org/1.0"

def initialize(username, password)
@credentials = { username: username, password: password }
@headers = { basic_auth: @credentials }
end

def commit_comments(slug, sha, options={})
options.merge!(@headers)
response = self.class.get("/repositories/#{slug}/changesets/#{sha}/comments", options)
openstruct(response.parsed_response)
end

def create_commit_comment(slug, sha, body, path, position, runner = nil, commit_sha = nil, options={})
options.merge!(@headers)
options[:body] = {
content: body,
line_to: position,
filename: path
}
self.class.post("/repositories/#{slug}/changesets/#{sha}/comments", options)
end

def pull_comments(slug, pr_id, options={})
options.merge!(@headers)
response = self.class.get("/repositories/#{slug}/pullrequests/#{pr_id}/comments", options)
openstruct(response.parsed_response)
end

def pull_requests(slug, options={})
options.merge!(@headers)
response = self.class.get("https://api.bitbucket.org/2.0/repositories/#{slug}/pullrequests?state=OPEN", options)
openstruct(response.parsed_response['values'])
end

def create_pull_comment(slug, pull_id, body, sha, path, position, options={})
options.merge!(@headers)
options[:body] = {
content: body,
line_to: position,
filename: path
}
self.class.post("/repositories/#{slug}/pullrequests/#{pull_id}/comments", options)
end

def openstruct(response)
response.map { |r| OpenStruct.new(r) }
end
end
6 changes: 5 additions & 1 deletion lib/pronto/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ def initialize(config_hash = ConfigFile.new.to_h)
@config_hash = config_hash
end

%w(github gitlab).each do |service|
%w(github gitlab bitbucket).each do |service|
ConfigFile::EMPTY[service].each do |key, _|
name = "#{service}_#{key}"
define_method(name) { ENV[name.upcase] || @config_hash[service][key] }
Expand All @@ -21,6 +21,10 @@ def github_hostname
URI.parse(github_web_endpoint).host
end

def bitbucket_hostname
URI.parse(bitbucket_web_endpoint).host
end

def max_warnings
@config_hash['max_warnings']
end
Expand Down
6 changes: 6 additions & 0 deletions lib/pronto/config_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ class ConfigFile
'api_private_token' => nil,
'api_endpoint' => nil
},
'bitbucket' => {
'slug' => nil,
'username' => nil,
'password' => nil,
'web_endpoint' => 'https://bitbucket.org/'
},
'runners' => [],
'formatters' => [],
'max_warnings' => nil,
Expand Down
29 changes: 29 additions & 0 deletions lib/pronto/formatter/bitbucket_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module Pronto
module Formatter
class BitbucketFormatter
def format(messages, repo, patches)
client = Bitbucket.new(repo)

commit_messages = messages.uniq.map do |message|
sha = message.commit_sha
body = message.msg
path = message.path
position = message.line.new_lineno

create_comment(client, sha, body, path, position)
end

"#{commit_messages.compact.count} Pronto messages posted to BitBucket"
end

private

def create_comment(client, sha, body, path, position)
comment = Bitbucket::Comment.new(sha, body, path, position)
comments = client.commit_comments(sha)
existing = comments.any? { |c| comment == c }
client.create_commit_comment(comment) unless existing
end
end
end
end
29 changes: 29 additions & 0 deletions lib/pronto/formatter/bitbucket_pull_request_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module Pronto
module Formatter
class BitbucketPullRequestFormatter
def format(messages, repo, patches)
client = Bitbucket.new(repo)
head = repo.head_commit_sha

commit_messages = messages.uniq.map do |message|
body = message.msg
path = message.path
line = message.line.line.new_lineno

create_comment(client, head, body, path, line)
end

"#{commit_messages.compact.count} Pronto messages posted to BitBucket"
end

private

def create_comment(client, sha, body, path, position)
comment = Bitbucket::Comment.new(sha, body, path, position)
comments = client.pull_comments(sha)
existing = comments.any? { |c| comment == c }
client.create_pull_comment(comment) unless existing
end
end
end
end
2 changes: 2 additions & 0 deletions lib/pronto/formatter/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ def self.names
'github' => GithubFormatter,
'github_pr' => GithubPullRequestFormatter,
'gitlab' => GitlabFormatter,
'bitbucket' => BitbucketFormatter,
'bitbucket_pr' => BitbucketPullRequestFormatter,
'json' => JsonFormatter,
'checkstyle' => CheckstyleFormatter,
'text' => TextFormatter,
Expand Down
1 change: 1 addition & 0 deletions pronto.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency('thor', '~> 0.19.0')
s.add_runtime_dependency('octokit', '~> 4.3', '>= 4.1.0')
s.add_runtime_dependency('gitlab', '~> 3.6', '>= 3.4.0')
s.add_runtime_dependency('httparty', '~> 0.13.7')
s.add_development_dependency('rake', '~> 11.0')
s.add_development_dependency('rspec', '~> 3.4')
s.add_development_dependency('rspec-its', '~> 1.2')
Expand Down
71 changes: 71 additions & 0 deletions spec/pronto/bitbucket_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
module Pronto
describe Bitbucket do
let(:bitbucket) { described_class.new(repo) }

let(:repo) do
double(remote_urls: ['[email protected]:mmozuras/pronto.git'], branch: nil)
end
let(:sha) { '61e4bef' }
let(:comment) { double(content: 'note', filename: 'path', line_to: 1, position: 1) }

describe '#slug' do
let(:repo) { double(remote_urls: ['[email protected]:mmozuras/pronto']) }
subject { bitbucket.commit_comments(sha) }

context 'git remote without .git suffix' do
specify do
BitbucketClient.any_instance
.should_receive(:commit_comments)
.with('mmozuras/pronto', sha)
.once
.and_return([comment])

subject
end
end
end

describe '#commit_comments' do
subject { bitbucket.commit_comments(sha) }

context 'three requests for same comments' do
specify do
BitbucketClient.any_instance
.should_receive(:commit_comments)
.with('mmozuras/pronto', sha)
.once
.and_return([comment])

subject
subject
subject
end
end
end

describe '#pull_comments' do
subject { bitbucket.pull_comments(sha) }

context 'three requests for same comments' do
specify do
BitbucketClient.any_instance
.should_receive(:pull_requests)
.once
.and_return([])

BitbucketClient.any_instance
.should_receive(:pull_comments)
.with('mmozuras/pronto', 10)
.once
.and_return([comment])

ENV['PULL_REQUEST_ID'] = '10'

subject
subject
subject
end
end
end
end
end
Loading

0 comments on commit 200a660

Please sign in to comment.