Merge pull request #164 from travis-ci/rkh-v3-branches

[DO NOT MERGE] API v3: use branches table
This commit is contained in:
Konstantin Haase 2015-02-24 16:28:17 +01:00
commit cbe5d0d92b
20 changed files with 163 additions and 44 deletions

View File

@ -50,7 +50,7 @@ GIT
GIT
remote: git://github.com/travis-ci/travis-core.git
revision: 4cfa414b1d384e518d567c70d572b34a74cbf0bf
revision: 3c031d6fb8dbbb415e5d2ef3b2af68a80d361933
specs:
travis-core (0.0.1)
actionmailer (~> 3.2.19)
@ -61,7 +61,7 @@ GIT
hashr (~> 0.0.19)
metriks (~> 0.9.7)
multi_json
pusher (~> 0.12.0)
pusher (~> 0.14.0)
railties (~> 3.2.19)
rake
redis (~> 3.0)
@ -95,6 +95,7 @@ PATH
remote: .
specs:
travis-api (0.0.1)
composite_primary_keys (~> 5.0)
memcachier
mustermann (~> 0.4)
pg (~> 0.13.2)
@ -154,6 +155,8 @@ GEM
coderay (1.1.0)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
composite_primary_keys (5.0.14)
activerecord (~> 3.2.0, >= 3.2.9)
connection_pool (2.1.1)
daemons (1.1.9)
dalli (2.7.2)
@ -168,7 +171,7 @@ GEM
dotenv (0.7.0)
equalizer (0.0.9)
erubis (2.7.0)
eventmachine (1.0.4)
eventmachine (1.0.7)
factory_girl (2.4.2)
activesupport
faraday (0.9.1)
@ -187,9 +190,9 @@ GEM
hashr (0.0.22)
hike (1.2.3)
hitimes (1.2.2)
httpclient (2.3.4.1)
httpclient (2.6.0.1)
i18n (0.6.11)
ice_nine (0.11.0)
ice_nine (0.11.1)
journey (1.0.4)
json (1.8.1)
kgio (2.9.2)
@ -224,10 +227,10 @@ GEM
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pusher (0.12.0)
httpclient (~> 2.3.0)
pusher (0.14.4)
httpclient (~> 2.5)
multi_json (~> 1.0)
signature (~> 0.1.6)
signature (~> 0.1.8)
rack (1.4.5)
rack-attack (4.2.0)
rack
@ -274,7 +277,7 @@ GEM
json
redis (>= 3.0.6)
redis-namespace (>= 1.3.1)
signature (0.1.7)
signature (0.1.8)
simple_states (1.0.1)
activesupport
hashr (~> 0.0.10)
@ -324,7 +327,7 @@ GEM
raindrops (~> 0.7)
useragent (0.10.0)
uuidtools (2.1.5)
virtus (1.0.3)
virtus (1.0.4)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)

View File

@ -24,6 +24,10 @@ module Travis::API::V3
visible? build.repository
end
def branch_visible?(branch)
visible? branch.repository
end
def organization_visible?(organization)
unrestricted_api?
end

View File

@ -1,3 +1,5 @@
require 'composite_primary_keys'
module Travis::API::V3
module Models
extend ConstantResolver

View File

@ -0,0 +1,8 @@
module Travis::API::V3
class Models::Branch < Model
belongs_to :repository
belongs_to :last_build, class_name: 'Travis::API::V3::Models::Build'.freeze
has_many :builds, foreign_key: [:repository_id, :branch], primary_key: [:repository_id, :name], order: 'id DESC'.freeze, conditions: { event_type: 'push' }
has_many :commits, foreign_key: [:repository_id, :branch], primary_key: [:repository_id, :name], order: 'id DESC'.freeze
end
end

View File

@ -2,7 +2,8 @@ module Travis::API::V3
class Models::Repository < Model
has_many :commits, dependent: :delete_all
has_many :requests, dependent: :delete_all
has_many :builds, dependent: :delete_all
has_many :branches, dependent: :delete_all, order: 'id DESC'.freeze
has_many :builds, dependent: :delete_all, order: 'id DESC'.freeze
has_many :permissions, dependent: :delete_all
has_many :users, through: :permissions
@ -12,12 +13,44 @@ module Travis::API::V3
class_name: 'Travis::API::V3::Models::Build'.freeze,
order: 'id DESC'.freeze
has_one :default_branch,
foreign_key: [:repository_id, :name],
primary_key: [:id, :default_branch],
class_name: 'Travis::API::V3::Models::Branch'.freeze
after_initialize do
update_attributes! default_branch_name: 'master'.freeze unless default_branch_name
end
def slug
@slug ||= "#{owner_name}/#{name}"
end
def last_build_on(branch)
builds.order('id DESC'.freeze).where(branch: branch, event_type: 'push'.freeze).first
def default_branch_name
read_attribute(:default_branch)
end
def default_branch_name=(value)
write_attribute(:default_branch, value)
end
def default_branch
super || branch(default_branch_name, create_without_build: true)
end
# Creates a branch object on the fly if it doesn't exist.
#
# Will not create a branch object if we don't have any builds for it unless
# the create_without_build option is set to true.
def branch(name, create_without_build: false)
return nil unless branch = branches.where(name: name).first_or_initialize
return branch unless branch.new_record?
return nil unless create_without_build or branch.builds.any?
branch.last_build = branch.builds.first
branch.save!
branch
rescue ActiveRecord::RecordNotUnique
branches.where(name: name).first
end
end
end

View File

@ -0,0 +1,10 @@
module Travis::API::V3
class Queries::Branch < Query
params :name
def find(repository)
return repository.branch(name) if name
raise WrongParams, 'missing branch.name'.freeze
end
end
end

View File

@ -11,6 +11,7 @@ module Travis::API::V3
all = Models::Repository
all = all.where(active: bool(active)) unless active.nil?
all = all.where(private: bool(private)) unless private.nil?
all = all.includes(:default_branch) # TODO: use includes params
all
end
end

View File

@ -10,13 +10,22 @@ module Travis::API::V3
args.select { |key, value| !value.nil? }
end
def href(type, script_name: nil, **args)
expander = EXPANDER_CACHE[[type, script_name, args.keys]] ||= begin
resource = Routes.resources.detect { |r| r.identifier == type }
unprefixed = args.keys.reject { |a| a.to_s.include? ?..freeze }
route = resource.route
route &&= Mustermann.new(script_name, type: :identity) + route if script_name and not script_name.empty?
generate_expander(route, type, unprefixed)
def href(type, string_args = nil, script_name: nil, **args)
args.merge! string_args if string_args
expander = EXPANDER_CACHE[[type, script_name, args.keys]] ||= begin
resource = Routes.resources.detect { |r| r.identifier == type }
route = resource.route
route &&= Mustermann.new(script_name, type: :identity) + route if script_name and not script_name.empty?
key_mapping = {}
args.keys.each do |key|
case key.to_s
when /\./ then key_mapping[key.to_sym] = key unless key.is_a? Symbol
when /^(.+)_id$/ then key_mapping[:"#{$1}.id"] = key
else key_mapping[:"#{type}.#{key}"] = key
end
end
generate_expander(route, key_mapping)
end
expander.call(args)
@ -24,11 +33,11 @@ module Travis::API::V3
private
def generate_expander(route, prefix, unprefixed)
def generate_expander(route, key_mapping)
return proc { |**| } unless route.respond_to? :expand
proc do |**args|
unprefixed.each { |key| args[:"#{prefix}.#{key}"] = args.delete(key) }
route.expand(**args)
proc do |args|
key_mapping.each { |a, b| args[a] = args.delete(b) }
route.expand(:ignore, **args)
end
end
end

View File

@ -0,0 +1,8 @@
require 'travis/api/v3/renderer/model_renderer'
module Travis::API::V3
class Renderer::Branch < Renderer::ModelRenderer
representation(:minimal, :name, :last_build)
representation(:standard, :name, :repository, :last_build)
end
end

View File

@ -33,8 +33,8 @@ module Travis::API::V3
def href
return @href if defined? @href # allows setting href to nil
return unless self.class.type and model.respond_to? :id and model.id
@href = Renderer.href(self.class.type, script_name: script_name, id: model.id)
return unless self.class.type and model.respond_to? :attributes
@href = Renderer.href(self.class.type, model.attributes, script_name: script_name)
end
def render(representation)

View File

@ -5,15 +5,6 @@ module Travis::API::V3
representation(:minimal, :id, :slug)
representation(:standard, :id, :name, :slug, :description, :github_language, :active, :private, :owner, :last_build, :default_branch)
def default_branch
branch_name = model.default_branch || 'master'.freeze
{
:@type => 'branch'.freeze,
:name => branch_name,
:last_build => model.last_build_on(branch_name)
}
end
def active
!!model.active
end

View File

@ -12,6 +12,11 @@ module Travis::API::V3
get :find
post :create
end
resource :branch do
route '/branch/{branch.name}'
get :find
end
end
resource :repositories do

View File

@ -34,7 +34,7 @@ module Travis::API::V3
end
def route(value)
current_resource.route = prefix + value
current_resource.route = Mustermann.new(prefix) + Mustermann.new(value)
end
def get(*args)

View File

@ -2,6 +2,7 @@ module Travis::API::V3
module Services
extend ConstantResolver
Branch = Module.new { extend Services }
Build = Module.new { extend Services }
Organization = Module.new { extend Services }
Organizations = Module.new { extend Services }

View File

@ -0,0 +1,7 @@
module Travis::API::V3
class Services::Branch::Find < Service
def run!
find(:branch, find(:repository))
end
end
end

View File

@ -12,6 +12,8 @@ describe Travis::API::V3::ServiceIndex do
"find" => [{"request-method"=>"GET", "uri-template"=>"#{path}repo/{repository.id}"}] },
"repositories" => {
"for_current_user" => [{"request-method"=>"GET", "uri-template"=>"#{path}repos"}] },
"branch" => {
"find" => [{"request-method"=>"GET", "uri-template"=>"#{path}repo/{repository.id}/branch/{branch.name}"}]},
"build" => {
"find" => [{"request-method"=>"GET", "uri-template"=>"#{path}build/{build.id}"}] },
"organizations" => {

View File

@ -0,0 +1,29 @@
require 'spec_helper'
describe Travis::API::V3::Services::Repository::Find do
let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first }
before { repo.default_branch.save! }
describe "public repository, existing branch" do
before { get("/v3/repo/#{repo.id}/branch/master") }
example { expect(last_response).to be_ok }
example { expect(JSON.load(body)).to be == {
"@type" => "branch",
"@href" => "/v3/repo/#{repo.id}/branch/master",
"name" => "master",
"repository" => {
"@type" => "repository",
"@href" => "/v3/repo/#{repo.id}",
"id" => repo.id,
"slug" => "svenfuchs/minimal"},
"last_build" => {
"@type" => "build",
"@href" => "/v3/build/#{repo.last_build.id}",
"id" => repo.last_build.id,
"number" => "3",
"state" => "configured",
"duration" => nil,
"started_at" => "2010-11-12T13:00:00Z",
"finished_at" => nil}}}
end
end

View File

@ -40,6 +40,7 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do
"finished_at" => "2010-11-12T12:30:20Z"},
"default_branch" => {
"@type" => "branch",
"@href" => "/v3/repo/#{repo.id}/branch/master",
"name" => "master",
"last_build" => {
"@type" => "build",

View File

@ -31,6 +31,7 @@ describe Travis::API::V3::Services::Repository::Find do
"finished_at" => "2010-11-12T12:30:20Z"},
"default_branch" => {
"@type" => "branch",
"@href" => "/v3/repo/#{repo.id}/branch/master",
"name" => "master",
"last_build" => {
"@type" => "build",
@ -114,6 +115,7 @@ describe Travis::API::V3::Services::Repository::Find do
"finished_at" => "2010-11-12T12:30:20Z"},
"default_branch" => {
"@type" => "branch",
"@href" => "/v3/repo/#{repo.id}/branch/master",
"name" => "master",
"last_build" => {
"@type" => "build",
@ -182,6 +184,7 @@ describe Travis::API::V3::Services::Repository::Find do
"finished_at" => "2010-11-12T12:30:20Z"},
"default_branch" => {
"@type" => "branch",
"@href" => "/v3/repo/#{repo.id}/branch/master",
"name" => "master",
"last_build" => {
"@type" => "build",
@ -256,6 +259,7 @@ describe Travis::API::V3::Services::Repository::Find do
"finished_at" => "2010-11-12T12:30:20Z"},
"default_branch" => {
"@type" => "branch",
"@href" => "/v3/repo/#{repo.id}/branch/master",
"name" => "master",
"last_build" => {
"@type" => "build",

View File

@ -288,14 +288,15 @@ Gem::Specification.new do |s|
s.add_dependency 'travis-support'
s.add_dependency 'travis-core'
s.add_dependency 'pg', '~> 0.13.2'
s.add_dependency 'thin', '~> 1.4'
s.add_dependency 'sinatra', '~> 1.3'
s.add_dependency 'sinatra-contrib', '~> 1.3'
s.add_dependency 'mustermann', '~> 0.4'
s.add_dependency 'redcarpet', '~> 2.1'
s.add_dependency 'rack-ssl', '~> 1.3', '>= 1.3.3'
s.add_dependency 'rack-contrib', '~> 1.1'
s.add_dependency 'pg', '~> 0.13.2'
s.add_dependency 'composite_primary_keys', '~> 5.0'
s.add_dependency 'thin', '~> 1.4'
s.add_dependency 'sinatra', '~> 1.3'
s.add_dependency 'sinatra-contrib', '~> 1.3'
s.add_dependency 'mustermann', '~> 0.4'
s.add_dependency 'redcarpet', '~> 2.1'
s.add_dependency 'rack-ssl', '~> 1.3', '>= 1.3.3'
s.add_dependency 'rack-contrib', '~> 1.1'
s.add_dependency 'memcachier'
s.add_dependency 'useragent'
end