Skip to content

Commit 970fb26

Browse files
committed
Adds bitbucket support
This adds backend support for bitbucket repositories. Missing: - An interface to add bitbucket projects - Remove some hardcoded github links (mostly views) Limitations: - Bitbucket API only allows fetching 15 commits at a time.
1 parent e354dd1 commit 970fb26

File tree

8 files changed

+136
-24
lines changed

8 files changed

+136
-24
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ gem 'devise', '~> 3.2.2'
2020
gem 'omniauth', '~> 1.1.4'
2121
gem 'omniauth-github', '~> 1.1.1'
2222
gem 'octokit', '~> 2.7.0'
23+
gem 'sawyer', '~> 0.5.2'
2324
gem 'twitter_bootstrap_form_for', github: 'stouset/twitter_bootstrap_form_for'
2425
gem 'twitter-bootstrap-rails', github: 'seyhunak/twitter-bootstrap-rails', branch: 'bootstrap3'
2526
gem 'sdoc', group: :doc, require: false

Gemfile.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ DEPENDENCIES
277277
rails (= 4.0.2)
278278
rspec-rails (~> 3.0.0.beta)
279279
sass-rails (~> 4.0.0)
280+
sawyer (~> 0.5.2)
280281
sdoc
281282
shoulda-matchers (~> 2.5.0)
282283
sqlite3 (~> 1.3.8)

app/controllers/projects_controller.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ def create
3333
:client_secret => CONFIG['github']['secret']
3434
begin
3535
repo = client.repo project_name
36-
@project = Project.find_or_create_by full_name: repo.full_name
37-
@project.update_github_info repo
36+
@project = Project.find_or_create_by host: "github", full_name: repo.full_name
37+
@project.update_repository_info repo
3838
redirect_to @project
3939
rescue Octokit::NotFound
4040
redirect_to projects_path, alert: "Project not found"

app/models/project.rb

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ class Project < ActiveRecord::Base
44

55
validates :full_name, uniqueness: true, presence: true
66
validates :github_id, uniqueness: true, presence: true
7+
validates :host, inclusion: [ "github", "bitbucket" ], presence: true
78

8-
def update_github_info repo
9+
def update_repository_info repo
910
self.github_id = repo.id
1011
self.name = repo.name
1112
self.full_name = repo.full_name
@@ -16,22 +17,34 @@ def update_github_info repo
1617
self.save!
1718
end
1819

20+
def repository_client
21+
if host == "github"
22+
Github.new
23+
elsif host == "bitbucket"
24+
Bitbucket.new
25+
end
26+
end
27+
1928
def github_url
20-
"https://github.com/#{full_name}"
29+
repository_client.repository_url self
2130
end
2231

2332
def source_github_url
24-
"https://github.com/#{source_full_name}"
33+
repository_client.source_repository_url self
34+
end
35+
36+
def raw_commits
37+
repository_client.commits self
38+
end
39+
40+
def repository_info
41+
repository_client.repository_info self
2542
end
2643

2744
def new_commits
2845
begin
2946
commits = Timeout::timeout(90) do
30-
client = Octokit::Client.new \
31-
:client_id => CONFIG['github']['key'],
32-
:client_secret => CONFIG['github']['secret'],
33-
:per_page => 100
34-
client.commits(full_name).
47+
raw_commits.
3548
# Filter merge request
3649
select{|c| !(c.commit.message =~ /^(Merge\s|auto\smerge)/)}.
3750
# Filter fake emails
@@ -132,26 +145,14 @@ def self.update_cache
132145
end
133146
end
134147

135-
def github_info
136-
client = Octokit::Client.new \
137-
:client_id => CONFIG['github']['key'],
138-
:client_secret => CONFIG['github']['secret']
139-
if github_id.present?
140-
client.get("/repositories/#{github_id}")
141-
else
142-
client.repo(full_name)
143-
end
144-
end
145-
146148
def update_info
147149
begin
148-
update_github_info(github_info)
150+
update_repository_info(repository_info)
149151
rescue Octokit::BadGateway, Octokit::NotFound, Octokit::InternalServerError,
150152
Errno::ETIMEDOUT, Net::ReadTimeout, Faraday::Error::ConnectionFailed => e
151153
Rails.logger.info "Project ##{id}: #{e.class} happened"
152154
rescue StandardError => e
153155
Airbrake.notify(e)
154156
end
155157
end
156-
157158
end

app/services/bitbucket.rb

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
require 'sawyer'
2+
3+
class Bitbucket
4+
Repository = Struct.new :id, :name, :full_name, :source_full_name, :description, :watchers_count, :language
5+
6+
Changeset = Struct.new :sha, :commit, :author
7+
Commit = Struct.new :author, :message, :commiter
8+
Committer = Struct.new :date
9+
Author = Struct.new :email, :name
10+
11+
attr_reader :agent
12+
13+
def initialize
14+
@agent = Sawyer::Agent.new("https://bitbucket.org")
15+
end
16+
17+
def repository_info repository
18+
data = request :get, repository_path(repository.full_name)
19+
20+
Repository.new(
21+
data.slug,
22+
data.name,
23+
repository.full_name,
24+
(data.fork_of.owner + "/" + data.fork_of.slug rescue ''),
25+
data.description,
26+
data.followers_count,
27+
data.language)
28+
end
29+
30+
def commits repository
31+
data = request :get, changesets_path(repository.full_name)
32+
33+
data.changesets.map do |cs|
34+
author_pieces = cs.raw_author.match(/^(.*) <(.*@.*)>$/)
35+
36+
date = DateTime.parse(cs.utctimestamp)
37+
author = Author.new(author_pieces[2], author_pieces[1])
38+
commit = Commit.new(author, cs.message, Committer.new(date))
39+
Changeset.new(cs.raw_node, commit)
40+
end
41+
end
42+
43+
def repository_url project
44+
"https://bitbucket.org/#{project.full_name}"
45+
end
46+
47+
def source_repository_url project
48+
"https://bitbucket.org/#{project.source_full_name}"
49+
end
50+
51+
protected
52+
def repository_path full_name
53+
"#{base_path}#{full_name}"
54+
end
55+
56+
def changesets_path full_name
57+
"#{base_path}#{full_name}/changesets?limit=15"
58+
end
59+
60+
def base_path
61+
"/api/1.0/repositories/"
62+
end
63+
64+
def request method, path
65+
agent.call(method, path).data
66+
end
67+
end

app/services/github.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class Github
2+
def initialize
3+
@client = Octokit::Client.new(
4+
:client_id => CONFIG['github']['key'],
5+
:client_secret => CONFIG['github']['secret'],
6+
:per_page => 100)
7+
end
8+
9+
attr_reader :client
10+
11+
def commits project
12+
client.commits project.full_name
13+
end
14+
15+
def repository_info project
16+
if project.github_id.present?
17+
client.get "/repositories/#{project.github_id}"
18+
else
19+
client.repo full_name
20+
end
21+
end
22+
23+
def repository_url project
24+
"https://github.com/#{project.full_name}"
25+
end
26+
27+
def source_repository_url project
28+
"https://github.com/#{project.source_full_name}"
29+
end
30+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class AddProjectHost < ActiveRecord::Migration
2+
class Project < ActiveRecord::Base
3+
end
4+
5+
def change
6+
add_column :projects, :host, :string, default: 'github'
7+
8+
# Update all existing projects
9+
Project.where(host: nil).update_all(host: 'github')
10+
end
11+
end

db/schema.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#
1212
# It's strongly recommended that you check this file into your version control system.
1313

14-
ActiveRecord::Schema.define(version: 20140209041123) do
14+
ActiveRecord::Schema.define(version: 20140223061035) do
1515

1616
create_table "deposits", force: true do |t|
1717
t.integer "project_id"
@@ -41,6 +41,7 @@
4141
t.string "last_commit"
4242
t.integer "available_amount_cache"
4343
t.string "github_id"
44+
t.string "host", default: "github"
4445
end
4546

4647
add_index "projects", ["full_name"], name: "index_projects_on_full_name", unique: true

0 commit comments

Comments
 (0)