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

View File

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

View File

@ -1,3 +1,5 @@
require 'composite_primary_keys'
module Travis::API::V3 module Travis::API::V3
module Models module Models
extend ConstantResolver 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 class Models::Repository < Model
has_many :commits, dependent: :delete_all has_many :commits, dependent: :delete_all
has_many :requests, 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 :permissions, dependent: :delete_all
has_many :users, through: :permissions has_many :users, through: :permissions
@ -12,12 +13,44 @@ module Travis::API::V3
class_name: 'Travis::API::V3::Models::Build'.freeze, class_name: 'Travis::API::V3::Models::Build'.freeze,
order: 'id DESC'.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 def slug
@slug ||= "#{owner_name}/#{name}" @slug ||= "#{owner_name}/#{name}"
end end
def last_build_on(branch) def default_branch_name
builds.order('id DESC'.freeze).where(branch: branch, event_type: 'push'.freeze).first 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 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 = Models::Repository
all = all.where(active: bool(active)) unless active.nil? all = all.where(active: bool(active)) unless active.nil?
all = all.where(private: bool(private)) unless private.nil? all = all.where(private: bool(private)) unless private.nil?
all = all.includes(:default_branch) # TODO: use includes params
all all
end end
end end

View File

@ -10,13 +10,22 @@ module Travis::API::V3
args.select { |key, value| !value.nil? } args.select { |key, value| !value.nil? }
end end
def href(type, script_name: nil, **args) def href(type, string_args = nil, script_name: nil, **args)
expander = EXPANDER_CACHE[[type, script_name, args.keys]] ||= begin args.merge! string_args if string_args
resource = Routes.resources.detect { |r| r.identifier == type }
unprefixed = args.keys.reject { |a| a.to_s.include? ?..freeze } expander = EXPANDER_CACHE[[type, script_name, args.keys]] ||= begin
route = resource.route resource = Routes.resources.detect { |r| r.identifier == type }
route &&= Mustermann.new(script_name, type: :identity) + route if script_name and not script_name.empty? route = resource.route
generate_expander(route, type, unprefixed) 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 end
expander.call(args) expander.call(args)
@ -24,11 +33,11 @@ module Travis::API::V3
private private
def generate_expander(route, prefix, unprefixed) def generate_expander(route, key_mapping)
return proc { |**| } unless route.respond_to? :expand return proc { |**| } unless route.respond_to? :expand
proc do |**args| proc do |args|
unprefixed.each { |key| args[:"#{prefix}.#{key}"] = args.delete(key) } key_mapping.each { |a, b| args[a] = args.delete(b) }
route.expand(**args) route.expand(:ignore, **args)
end end
end 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 def href
return @href if defined? @href # allows setting href to nil return @href if defined? @href # allows setting href to nil
return unless self.class.type and model.respond_to? :id and model.id return unless self.class.type and model.respond_to? :attributes
@href = Renderer.href(self.class.type, script_name: script_name, id: model.id) @href = Renderer.href(self.class.type, model.attributes, script_name: script_name)
end end
def render(representation) def render(representation)

View File

@ -5,15 +5,6 @@ module Travis::API::V3
representation(:minimal, :id, :slug) representation(:minimal, :id, :slug)
representation(:standard, :id, :name, :slug, :description, :github_language, :active, :private, :owner, :last_build, :default_branch) 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 def active
!!model.active !!model.active
end end

View File

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

View File

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

View File

@ -2,6 +2,7 @@ module Travis::API::V3
module Services module Services
extend ConstantResolver extend ConstantResolver
Branch = Module.new { extend Services }
Build = Module.new { extend Services } Build = Module.new { extend Services }
Organization = Module.new { extend Services } Organization = Module.new { extend Services }
Organizations = 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}"}] }, "find" => [{"request-method"=>"GET", "uri-template"=>"#{path}repo/{repository.id}"}] },
"repositories" => { "repositories" => {
"for_current_user" => [{"request-method"=>"GET", "uri-template"=>"#{path}repos"}] }, "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" => { "build" => {
"find" => [{"request-method"=>"GET", "uri-template"=>"#{path}build/{build.id}"}] }, "find" => [{"request-method"=>"GET", "uri-template"=>"#{path}build/{build.id}"}] },
"organizations" => { "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"}, "finished_at" => "2010-11-12T12:30:20Z"},
"default_branch" => { "default_branch" => {
"@type" => "branch", "@type" => "branch",
"@href" => "/v3/repo/#{repo.id}/branch/master",
"name" => "master", "name" => "master",
"last_build" => { "last_build" => {
"@type" => "build", "@type" => "build",

View File

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

View File

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