diff --git a/app.rb b/app.rb
new file mode 100644
index 00000000..73675f10
--- /dev/null
+++ b/app.rb
@@ -0,0 +1,5 @@
+require 'sinatra'
+
+get '/' do
+ "
"
+end
\ No newline at end of file
diff --git a/lib/travis/api/v3.rb b/lib/travis/api/v3.rb
index 29589008..50daf610 100644
--- a/lib/travis/api/v3.rb
+++ b/lib/travis/api/v3.rb
@@ -17,12 +17,13 @@ module Travis
extend self
load_dir("#{__dir__}/v3")
- ClientError = Error .create(status: 400)
- NotFound = ClientError .create(:resource, status: 404, template: '%s not found (or insufficient access)')
- EnitityMissing = NotFound .create(type: 'not_found')
- WrongCredentials = ClientError .create('access denied', status: 403)
- LoginRequired = ClientError .create('login required', status: 403)
- WrongParams = ClientError .create('wrong parameters')
+ ClientError = Error .create(status: 400)
+ NotFound = ClientError .create(:resource, status: 404, template: '%s not found (or insufficient access)')
+ EntityMissing = NotFound .create(type: 'not_found')
+ WrongCredentials = ClientError .create('access denied', status: 403)
+ LoginRequired = ClientError .create('login required', status: 403)
+ InsufficientAccess = ClientError .create(status: 403)
+ WrongParams = ClientError .create('wrong parameters')
end
end
end
diff --git a/lib/travis/api/v3/access_control/generic.rb b/lib/travis/api/v3/access_control/generic.rb
index f5ea01a6..14b9db8b 100644
--- a/lib/travis/api/v3/access_control/generic.rb
+++ b/lib/travis/api/v3/access_control/generic.rb
@@ -1,5 +1,9 @@
module Travis::API::V3
class AccessControl::Generic
+ DEFAULT_LIMIT = 25
+ MAX_LIMT = 100
+ NO_LIMIT = 2 ** 62 - 1 # larges Fixnum on MRI
+
def self.for_request(type, payload, env)
end
@@ -18,6 +22,23 @@ module Travis::API::V3
false
end
+ # def limit(resource_type, value = nil)
+ # case value
+ # when ''.freeze, 'true'.freeze, true, nil then DEFAULT_LIMIT
+ # when 'false'.freeze, false then NO_LIMIT
+ # when /^\d+$/ then limit(resource_type, Integer(value))
+ # when 0..MAX_LIMIT then value
+ # end
+ # # # TODO move to config
+ # # value = Time.now.to_i if value == false or value == 'false'.freeze
+ # # value = 25 if value.nil? or value == ''.freezee or value ==
+ # # value = Integer(value)
+ # # value = 100 if value > 100 and not full_access?
+ # # value = 0 if value < 0
+ # rescue TypeError
+ # raise WrongParams, 'limit must be a positive integer'.freeze, resource_type: resource_type
+ # end
+
protected
def repository_visible?(repository)
diff --git a/lib/travis/api/v3/constant_resolver.rb b/lib/travis/api/v3/constant_resolver.rb
index 8e3219a9..f4431780 100644
--- a/lib/travis/api/v3/constant_resolver.rb
+++ b/lib/travis/api/v3/constant_resolver.rb
@@ -13,5 +13,10 @@ module Travis::API::V3
return key unless key.is_a? Symbol
resolver_cache[key] ||= const_get(key.to_s.camelize)
end
+
+ def extended(base)
+ base.extend(ConstantResolver)
+ super
+ end
end
end
diff --git a/lib/travis/api/v3/queries/requests.rb b/lib/travis/api/v3/queries/requests.rb
new file mode 100644
index 00000000..3ccc1c94
--- /dev/null
+++ b/lib/travis/api/v3/queries/requests.rb
@@ -0,0 +1,14 @@
+module Travis::API::V3
+ class Queries::Requests < Query
+ def schedule_for(repository)
+ perform_async(:build_request, type: 'api'.freeze, payload: payload, credentials: {})
+ end
+
+ def find(repository)
+ end
+
+ def payload
+ raise NotImplementedError
+ end
+ end
+end
diff --git a/lib/travis/api/v3/query.rb b/lib/travis/api/v3/query.rb
index 0d1061e6..3676065f 100644
--- a/lib/travis/api/v3/query.rb
+++ b/lib/travis/api/v3/query.rb
@@ -1,8 +1,27 @@
module Travis::API::V3
class Query
+ @@sidekiq_cache = Tool::ThreadLocal.new
+
+ # generate from eval to avoid additional string allocations on every params access
+ @@params_accessor = <<-RUBY
+ attr_writer :%s
+
+ def %s
+ return @%s if defined? @%s
+ return @%s = @params['%s.%s'.freeze] if @params.include? '%s.%s'.freeze
+ return @%s = @params['%s'.freeze]['%s'.freeze] if @params.include? '%s'.freeze and @params['%s'.freeze].is_a? Hash
+ return @%s = @params['%s'.freeze] if @params['@type'.freeze].nil? or @params['@type'.freeze] == '%s'.freeze
+ @%s = nil
+ end
+
+ def %s!
+ %s or raise WrongParams, 'missing %s.%s'.freeze, missing_field: '%s.%s'.freeze
+ end
+ RUBY
+
def self.params(*list, prefix: nil)
prefix ||= name[/[^:]+$/].underscore
- list.each { |e| class_eval("def #{e}; @params[\"#{prefix}.#{e}\".freeze]; end") }
+ list.each { |e| class_eval(@@params_accessor % { name: e, prefix: prefix }) }
end
attr_reader :params
@@ -11,6 +30,15 @@ module Travis::API::V3
@params = params
end
+ def perform_async(worker, *args)
+ class_name, queue, client = @@sidekiq_cache[identifier] ||= [
+ "Travis::Sidekiq::#{identifier.to_s.camelcase}".freeze,
+ identifier.to_s.pluralize.freeze
+ ]
+
+ ::Sidekiq::Client.push('queue'.freeze => queue, 'class'.freeze => class_name, 'args'.freeze => args)
+ end
+
def bool(value)
return false if value == 'false'.freeze
!!value
diff --git a/lib/travis/api/v3/renderer.rb b/lib/travis/api/v3/renderer.rb
index 0bc6b411..0eb08ab5 100644
--- a/lib/travis/api/v3/renderer.rb
+++ b/lib/travis/api/v3/renderer.rb
@@ -6,5 +6,14 @@ module Travis::API::V3
def format_date(date)
date && date.strftime('%Y-%m-%dT%H:%M:%SZ')
end
+
+ def get_attributes(object, *attributes, **defaults)
+ attributes.map { |a| [a, get_attribute(object, a, **defaults)] }.to_h
+ end
+
+ def get_attribute(object, attribute, **defaults)
+ value = object.public_send(attribute)
+ value.nil? ? defaults[attribute] : value
+ end
end
end
diff --git a/lib/travis/api/v3/renderer/accepted.rb b/lib/travis/api/v3/renderer/accepted.rb
new file mode 100644
index 00000000..2c0b4f93
--- /dev/null
+++ b/lib/travis/api/v3/renderer/accepted.rb
@@ -0,0 +1,12 @@
+module Travis::API::V3
+ module Renderer::Error
+ extend self
+
+ def render(type)
+ {
+ :@type => 'pending'.freeze,
+ :resource_type => type
+ }
+ end
+ end
+end
diff --git a/lib/travis/api/v3/renderer/collection.rb b/lib/travis/api/v3/renderer/collection.rb
index 25e61dde..8d4f8a61 100644
--- a/lib/travis/api/v3/renderer/collection.rb
+++ b/lib/travis/api/v3/renderer/collection.rb
@@ -1,4 +1,3 @@
-
module Travis::API::V3
module Renderer::Collection
extend self
diff --git a/lib/travis/api/v3/renderer/repository.rb b/lib/travis/api/v3/renderer/repository.rb
index 3313bcd9..0a9ec897 100644
--- a/lib/travis/api/v3/renderer/repository.rb
+++ b/lib/travis/api/v3/renderer/repository.rb
@@ -1,14 +1,11 @@
module Travis::API::V3
module Renderer::Repository
- DIRECT_ATTRIBUTES = %i[id name slug description github_language private]
+ DIRECT_ATTRIBUTES = %i[id name slug description github_language private active default_branch]
+ DEFAULTS = { active: false, default_branch: 'master' }
extend self
def render(repository)
- { :@type => 'repository'.freeze, active: !!repository.active, **direct_attributes(repository), **nested_resources(repository) }
- end
-
- def direct_attributes(repository)
- DIRECT_ATTRIBUTES.map { |a| [a, repository.public_send(a)] }.to_h
+ { :@type => 'repository'.freeze, **Renderer.get_attributes(repository, *DIRECT_ATTRIBUTES, **DEFAULTS), **nested_resources(repository) }
end
def nested_resources(repository)
diff --git a/lib/travis/api/v3/result.rb b/lib/travis/api/v3/result.rb
index 71e0b8fa..17d3570f 100644
--- a/lib/travis/api/v3/result.rb
+++ b/lib/travis/api/v3/result.rb
@@ -1,9 +1,9 @@
module Travis::API::V3
class Result
- attr_accessor :type, :resource
+ attr_accessor :type, :resource, :status
- def initialize(type, resource = [])
- @type, @resource = type, resource
+ def initialize(type, resource = [], status: 200)
+ @type, @resource, @status = type, resource, status
end
def respond_to_missing?(method, *)
diff --git a/lib/travis/api/v3/router.rb b/lib/travis/api/v3/router.rb
index a0fb3678..f03881f9 100644
--- a/lib/travis/api/v3/router.rb
+++ b/lib/travis/api/v3/router.rb
@@ -25,7 +25,7 @@ module Travis::API::V3
end
def render(result, env_params)
- V3.response(result.render)
+ V3.response(result.render, status: result.status)
end
def service_index(env)
diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb
index 5394d7dc..d1158278 100644
--- a/lib/travis/api/v3/routes.rb
+++ b/lib/travis/api/v3/routes.rb
@@ -5,17 +5,23 @@ module Travis::API::V3
resource :repository do
route '/repo/{repository.id}'
- get :find_repository
+ get :find
+
+ resource :requests do
+ route '/requests'
+ get :find
+ post :create
+ end
end
resource :repositories do
route '/repos'
- get :repositories_for_current_user
+ get :for_current_user
end
resource :organizations do
route '/orgs'
- get :organizations_for_current_user
+ get :for_current_user
end
end
end
diff --git a/lib/travis/api/v3/routes/dsl.rb b/lib/travis/api/v3/routes/dsl.rb
index fff4ff39..e4e08df2 100644
--- a/lib/travis/api/v3/routes/dsl.rb
+++ b/lib/travis/api/v3/routes/dsl.rb
@@ -14,6 +14,10 @@ module Travis::API::V3
@current_resource ||= nil
end
+ def prefix
+ @prefix ||= ""
+ end
+
def resource(type, &block)
resource = Routes::Resource.new(type)
with_resource(resource, &block)
@@ -22,13 +26,15 @@ module Travis::API::V3
def with_resource(resource)
resource_was, @current_resource = current_resource, resource
+ prefix_was, @prefix = @prefix, resource_was.route if resource_was
yield
ensure
+ @prefix = prefix_was if resource_was
@current_resource = resource_was
end
def route(value)
- current_resource.route = value
+ current_resource.route = prefix + value
end
def get(*args)
@@ -45,7 +51,7 @@ module Travis::API::V3
resource.services.each do |(request_method, sub_route), service|
route = sub_route ? prefix + sub_route : prefix
routes[route] ||= {}
- routes[route][request_method] = Services[service]
+ routes[route][request_method] = Services[resource.identifier][service]
end
end
self.routes.replace(routes)
diff --git a/lib/travis/api/v3/service.rb b/lib/travis/api/v3/service.rb
index d436eeea..61bfc07f 100644
--- a/lib/travis/api/v3/service.rb
+++ b/lib/travis/api/v3/service.rb
@@ -1,7 +1,12 @@
module Travis::API::V3
class Service
+ def self.helpers(*list)
+ include(*list.map { |e| ServiceHelpers[e] })
+ end
+
def self.result_type(type = nil)
- @result_type = type if type
+ @result_type = type if type
+ @result_type ||= parent.result_type if parent and parent.respond_to? :result_type
raise 'result type not set' unless defined? @result_type
@result_type
end
@@ -29,5 +34,9 @@ module Travis::API::V3
result = Result.new(self.class.result_type, result) unless result.is_a? Result
result
end
+
+ def accepted(type = self.class.result_type)
+ Result.new(:accepted, type, status: 202)
+ end
end
end
diff --git a/lib/travis/api/v3/service_helpers.rb b/lib/travis/api/v3/service_helpers.rb
new file mode 100644
index 00000000..9e4b03eb
--- /dev/null
+++ b/lib/travis/api/v3/service_helpers.rb
@@ -0,0 +1,5 @@
+module Travis::API::V3
+ module ServiceHelpers
+ extend ConstantResolver
+ end
+end
diff --git a/lib/travis/api/v3/service_helpers/repository.rb b/lib/travis/api/v3/service_helpers/repository.rb
new file mode 100644
index 00000000..71ba9336
--- /dev/null
+++ b/lib/travis/api/v3/service_helpers/repository.rb
@@ -0,0 +1,13 @@
+module Travis::API::V3
+ module ServiceHelpers::Repository
+ def repository
+ @repository ||= find_repository
+ end
+
+ def find_repository
+ not_found(true, :repository) unless repo = query(:repository).find
+ not_found(false, :repository) unless access_control.visible? repo
+ repo
+ end
+ end
+end
diff --git a/lib/travis/api/v3/service_index.rb b/lib/travis/api/v3/service_index.rb
index fbfe4072..8f413f01 100644
--- a/lib/travis/api/v3/service_index.rb
+++ b/lib/travis/api/v3/service_index.rb
@@ -27,15 +27,14 @@ module Travis::API::V3
routes.resources.each do |resource|
resources[resource.identifier] ||= {}
resource.services.each do |(request_method, sub_route), service|
- service &&= service.to_s.sub(/^#{resource.identifier}_|_#{resource.identifier}$/, ''.freeze)
- list = resources[resource.identifier][service] ||= []
- pattern = sub_route ? resource.route + sub_route : resource.route
+ list = resources[resource.identifier][service] ||= []
+ pattern = sub_route ? resource.route + sub_route : resource.route
pattern.to_templates.each do |template|
list << { 'request-method'.freeze => request_method, 'uri-template'.freeze => prefix + template }
end
end
end
- { resources: resources }
+ { :@type => 'home'.freeze, :resources => resources }
end
def render_json_home
@@ -43,9 +42,8 @@ module Travis::API::V3
routes.resources.each do |resource|
resource.services.each do |(request_method, sub_route), service|
- service &&= service.to_s.sub(/_#{resource.identifier}$/, ''.freeze)
- pattern = sub_route ? resource.route + sub_route : resource.route
- relation = "http://schema.travis-ci.com/rel/#{resource.identifier}/#{service}"
+ pattern = sub_route ? resource.route + sub_route : resource.route
+ relation = "http://schema.travis-ci.com/rel/#{resource.identifier}/#{service}"
pattern.to_templates.each do |template|
relations[relation] ||= {}
relations[relation][template] ||= { allow: [], vars: template.scan(/{\+?([^}]+)}/).flatten }
diff --git a/lib/travis/api/v3/services.rb b/lib/travis/api/v3/services.rb
index 83aa0c9f..4cdc4d22 100644
--- a/lib/travis/api/v3/services.rb
+++ b/lib/travis/api/v3/services.rb
@@ -1,5 +1,14 @@
module Travis::API::V3
module Services
extend ConstantResolver
+
+ Organizations = Module.new { extend Services }
+ Repositories = Module.new { extend Services }
+ Repository = Module.new { extend Services }
+ Requests = Module.new { extend Services }
+
+ def result_type
+ @resul_type ||= name[/[^:]+$/].underscore.to_sym
+ end
end
end
diff --git a/lib/travis/api/v3/services/find_repository.rb b/lib/travis/api/v3/services/find_repository.rb
deleted file mode 100644
index 481d706e..00000000
--- a/lib/travis/api/v3/services/find_repository.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-module Travis::API::V3
- class Services::FindRepository < Service
- result_type :repository
-
- def run!
- repository if repository and access_control.visible? repository
- end
-
- def repository
- not_found(true) if defined?(@repository) and @repository.nil?
- @repository ||= find_repository
- end
-
- def find_repository
- query.find
- end
- end
-end
diff --git a/lib/travis/api/v3/services/repositories_for_current_user.rb b/lib/travis/api/v3/services/organizations/for_current_user.rb
similarity index 64%
rename from lib/travis/api/v3/services/repositories_for_current_user.rb
rename to lib/travis/api/v3/services/organizations/for_current_user.rb
index 369422c1..42104de7 100644
--- a/lib/travis/api/v3/services/repositories_for_current_user.rb
+++ b/lib/travis/api/v3/services/organizations/for_current_user.rb
@@ -1,7 +1,5 @@
module Travis::API::V3
- class Services::RepositoriesForCurrentUser < Service
- result_type :repositories
-
+ class Services::Repositories::ForCurrentUser < Service
def run!
raise LoginRequired unless access_control.logged_in?
query.for_member(access_control.user)
diff --git a/lib/travis/api/v3/services/organizations_for_current_user.rb b/lib/travis/api/v3/services/repositories/for_current_user.rb
similarity index 64%
rename from lib/travis/api/v3/services/organizations_for_current_user.rb
rename to lib/travis/api/v3/services/repositories/for_current_user.rb
index 518fa838..b99af28f 100644
--- a/lib/travis/api/v3/services/organizations_for_current_user.rb
+++ b/lib/travis/api/v3/services/repositories/for_current_user.rb
@@ -1,7 +1,5 @@
module Travis::API::V3
- class Services::OrganizationsForCurrentUser < Service
- result_type :organizations
-
+ class Services::Organizations::ForCurrentUser < Service
def run!
raise LoginRequired unless access_control.logged_in?
query.for_member(access_control.user)
diff --git a/lib/travis/api/v3/services/repository/find.rb b/lib/travis/api/v3/services/repository/find.rb
new file mode 100644
index 00000000..29309a38
--- /dev/null
+++ b/lib/travis/api/v3/services/repository/find.rb
@@ -0,0 +1,9 @@
+module Travis::API::V3
+ class Services::Repository::Find < Service
+ helpers :repository
+
+ def run!
+ repository
+ end
+ end
+end
diff --git a/lib/travis/api/v3/services/requests/create.rb b/lib/travis/api/v3/services/requests/create.rb
new file mode 100644
index 00000000..46f2cb4c
--- /dev/null
+++ b/lib/travis/api/v3/services/requests/create.rb
@@ -0,0 +1,10 @@
+module Travis::API::V3
+ class Services::Requests::Create < Service
+ helpers :repository
+
+ def run
+ query.schedule_for(repository)
+ accepted
+ end
+ end
+end
diff --git a/lib/travis/api/v3/services/requests/find.rb b/lib/travis/api/v3/services/requests/find.rb
new file mode 100644
index 00000000..573d5201
--- /dev/null
+++ b/lib/travis/api/v3/services/requests/find.rb
@@ -0,0 +1,5 @@
+module Travis::API::V3
+ class Services::Requests::Find < Service
+ helpers :repository
+ end
+end
diff --git a/spec/v3/service_index_spec.rb b/spec/v3/service_index_spec.rb
index 83e872e8..4b840436 100644
--- a/spec/v3/service_index_spec.rb
+++ b/spec/v3/service_index_spec.rb
@@ -9,11 +9,14 @@ describe Travis::API::V3::ServiceIndex do
describe "custom json entry point" do
let(:expected_resources) {{
"repository" => {
- "find" => [{"request-method"=>"GET", "uri-template"=>"#{path}repo/{repository.id}"}] },
+ "find" => [{"request-method"=>"GET", "uri-template"=>"#{path}repo/{repository.id}"}] },
"repositories" => {
- "for_current_user" => [{"request-method"=>"GET", "uri-template"=>"#{path}repos"}] },
+ "for_current_user" => [{"request-method"=>"GET", "uri-template"=>"#{path}repos"}] },
"organizations" => {
- "for_current_user" => [{"request-method"=>"GET", "uri-template"=>"#{path}orgs"}] }
+ "for_current_user" => [{"request-method"=>"GET", "uri-template"=>"#{path}orgs"}] },
+ "requests" => {
+ "find" => [{"request-method"=>"GET", "uri-template"=>"#{path}repo/{repository.id}/requests"}],
+ "create" => [{"request-method"=>"POST", "uri-template"=>"#{path}repo/{repository.id}/requests"}]}
}}
describe 'with /v3 prefix' do
diff --git a/spec/v3/services/organizations_for_current_user_spec.rb b/spec/v3/services/organizations/organizations_for_current_user_spec.rb
similarity index 94%
rename from spec/v3/services/organizations_for_current_user_spec.rb
rename to spec/v3/services/organizations/organizations_for_current_user_spec.rb
index 69d94e44..10fa2740 100644
--- a/spec/v3/services/organizations_for_current_user_spec.rb
+++ b/spec/v3/services/organizations/organizations_for_current_user_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Travis::API::V3::Services::FindRepository do
+describe Travis::API::V3::Services::Organizations::ForCurrentUser do
let(:repo) { Repository.by_slug('svenfuchs/minimal').first }
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
diff --git a/spec/v3/services/repositories_for_current_user_spec.rb b/spec/v3/services/repositories/for_current_user_spec.rb
similarity index 95%
rename from spec/v3/services/repositories_for_current_user_spec.rb
rename to spec/v3/services/repositories/for_current_user_spec.rb
index a2a9f933..a0734c3d 100644
--- a/spec/v3/services/repositories_for_current_user_spec.rb
+++ b/spec/v3/services/repositories/for_current_user_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Travis::API::V3::Services::FindRepository do
+describe Travis::API::V3::Services::Repositories::ForCurrentUser do
let(:repo) { Repository.by_slug('svenfuchs/minimal').first }
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
@@ -23,6 +23,7 @@ describe Travis::API::V3::Services::FindRepository do
"github_language" => nil,
"active" => true,
"private" => true,
+ "default_branch" => "master",
"owner" => {
"@type" => "user",
"id" => repo.owner_id,
diff --git a/spec/v3/services/find_repository_spec.rb b/spec/v3/services/repository/find_spec.rb
similarity index 97%
rename from spec/v3/services/find_repository_spec.rb
rename to spec/v3/services/repository/find_spec.rb
index 0539d1d8..43c09392 100644
--- a/spec/v3/services/find_repository_spec.rb
+++ b/spec/v3/services/repository/find_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Travis::API::V3::Services::FindRepository do
+describe Travis::API::V3::Services::Repository::Find do
let(:repo) { Repository.by_slug('svenfuchs/minimal').first }
describe "public repository" do
@@ -15,6 +15,7 @@ describe Travis::API::V3::Services::FindRepository do
"github_language" => nil,
"active" => true,
"private" => false,
+ "default_branch" => "master",
"owner" => {
"@type" => "user",
"id" => repo.owner_id,
@@ -84,6 +85,7 @@ describe Travis::API::V3::Services::FindRepository do
"github_language" => nil,
"active" => true,
"private" => true,
+ "default_branch" => "master",
"owner" => {
"@type" => "user",
"id" => repo.owner_id,
@@ -138,6 +140,7 @@ describe Travis::API::V3::Services::FindRepository do
"github_language" => nil,
"active" => true,
"private" => true,
+ "default_branch" => "master",
"owner" => {
"@type" => "user",
"id" => repo.owner_id,
@@ -198,6 +201,7 @@ describe Travis::API::V3::Services::FindRepository do
"github_language" => nil,
"active" => true,
"private" => true,
+ "default_branch" => "master",
"owner" => {
"@type" => "user",
"id" => repo.owner_id,