diff --git a/lib/travis/api/app/endpoint/requests.rb b/lib/travis/api/app/endpoint/requests.rb index 4a5b73a0..6b2d94c3 100644 --- a/lib/travis/api/app/endpoint/requests.rb +++ b/lib/travis/api/app/endpoint/requests.rb @@ -1,12 +1,17 @@ require 'travis/api/app' +require 'travis/api/app/services/schedule_request' class Travis::Api::App class Endpoint class Requests < Endpoint - # DEPRECATED: this will be removed by 1st of December - post '/' do - Metriks.meter("api.request.restart").mark - respond_with service(:reset_model, params) + post '/', scope: :private do + if params[:request] && params[:request][:repository] + respond_with service(:schedule_request, params[:request]) + else + # DEPRECATED: this will be removed by 1st of December + Metriks.meter("api.request.restart").mark + respond_with service(:reset_model, params) + end end get '/' do diff --git a/lib/travis/api/app/helpers/respond_with.rb b/lib/travis/api/app/helpers/respond_with.rb index 55d38ed7..746152fb 100644 --- a/lib/travis/api/app/helpers/respond_with.rb +++ b/lib/travis/api/app/helpers/respond_with.rb @@ -8,14 +8,16 @@ class Travis::Api::App module RespondWith include Accept + STATUS = { + success: 200, + not_found: 404 + } + def respond_with(resource, options = {}) result = respond(resource, options) if result && response.content_type =~ /application\/json/ - if !params[:pretty].nil? && (params[:pretty].downcase == 'true' || params[:pretty].to_i > 0) - result = JSON.pretty_generate(result) - else - result = result.to_json - end + status STATUS[result[:result]] if result.is_a?(Hash) && result[:result].is_a?(Symbol) + result = prettify_result? ? JSON.pretty_generate(result) : result.to_json end halt result || 404 end @@ -48,6 +50,10 @@ class Travis::Api::App response || (resource ? error(406) : error(404)) end + def prettify_result? + !params[:pretty].nil? && (params[:pretty].downcase == 'true' || params[:pretty].to_i > 0) + end + def apply_service_responder(resource, options) responder = Responders::Service.new(self, resource, options) resource = responder.apply if responder.apply? diff --git a/lib/travis/api/app/responders/service.rb b/lib/travis/api/app/responders/service.rb index 55316b27..57942234 100644 --- a/lib/travis/api/app/responders/service.rb +++ b/lib/travis/api/app/responders/service.rb @@ -56,7 +56,7 @@ module Travis::Api # If it's nil we also pass it but yield not_found. def normalize(result) case result - when String, true, false + when Symbol, String, true, false { result: result } else result diff --git a/lib/travis/api/app/services/schedule_request.rb b/lib/travis/api/app/services/schedule_request.rb new file mode 100644 index 00000000..80fd9e20 --- /dev/null +++ b/lib/travis/api/app/services/schedule_request.rb @@ -0,0 +1,50 @@ +require 'multi_json' +require 'travis/sidekiq/build_request' +require 'travis/services/base' + +class Travis::Api::App + module Services + class ScheduleRequest < Travis::Services::Base + register :schedule_request + + def run + repo && active? ? schedule_request : not_found + end + + def messages + @messages ||= [] + end + + private + + def schedule_request + Metriks.meter('api.request.create').mark + Travis::Sidekiq::BuildRequest.perform_async(type: 'api', payload: payload, credentials: {}) + messages << { notice: 'Build request scheduled.' } + :success + end + + def not_found + messages << { error: "Repository #{slug} not found." } + :not_found + end + + def active? + Travis::Features.owner_active?(:request_create, repo.owner) + end + + def payload + MultiJson.encode(params.merge(user: { id: current_user.id })) + end + + def repo + @repo ||= Repository.by_slug(slug).first + end + + def slug + repo = params[:repository] || {} + repo.values_at(:owner_name, :name).join('/') + end + end + end +end diff --git a/spec/unit/endpoint/requests_spec.rb b/spec/unit/endpoint/requests_spec.rb new file mode 100644 index 00000000..4e04e82d --- /dev/null +++ b/spec/unit/endpoint/requests_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe Travis::Api::App::Endpoint::Requests do + include Travis::Testing::Stubs + + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: -1) } + let(:data) { { request: { repository: { owner_name: 'owner', name: 'name' }, branch: 'branch', config: { env: ['FOO=foo'] } } } } + let(:headers) { { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json, */*; q=0.01', 'HTTP_AUTHORIZATION' => %(token "#{token.token}") } } + let(:response) { post('/requests', data, headers) } + + before do + User.stubs(:find_by_github_id).returns(user) + User.stubs(:find).returns(user) + end + + describe 'POST to /' do + it 'needs to be authenticated' do + Travis::Api::App::AccessToken.stubs(:find_by_token).returns(nil) + expect(response.status).to eq 403 + end + + describe 'if the repository does not exist' do + it 'returns 404' do + expect(response.status).to eq 404 + end + + it 'includes a notice' do + expect(response.body).to eq '{"result":"not_found","flash":[{"error":"Repository owner/name not found."}]}' + end + end + + describe 'if successful' do + before do + Repository.stubs(:by_slug).returns([repo]) + Travis::Sidekiq::BuildRequest.stubs(:perform_async) + Travis::Features.stubs(:owner_active?).returns(true) + end + + it 'returns 200' do + expect(response.status).to eq 200 + end + + it 'includes a notice' do + expect(response.body).to eq '{"result":"success","flash":[{"notice":"Build request scheduled."}]}' + end + + it 'schedules the build request' do + payload = MultiJson.encode(data[:request].merge(user: { id: user.id })) + Travis::Sidekiq::BuildRequest.expects(:perform_async).with(type: 'api', payload: payload, credentials: {}) + response + end + end + end +end +