summaryrefslogtreecommitdiff
path: root/lib/api
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2013-05-30 16:46:16 +0300
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2013-05-30 16:46:16 +0300
commit1a595c3f0fb4a80aeb3efdaeb27d084f8029fd57 (patch)
tree5273c58118dd64c0700a88154eb0c0c7bec59397 /lib/api
parentd76520a3d091be232ce8a05fcaf605e2f268f821 (diff)
downloadgitlab-ci-1a595c3f0fb4a80aeb3efdaeb27d084f8029fd57.tar.gz
Remove runner functionality. Added api for builds
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/api.rb28
-rw-r--r--lib/api/builds.rb45
-rw-r--r--lib/api/entities.rb7
-rw-r--r--lib/api/helpers.rb104
4 files changed, 184 insertions, 0 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
new file mode 100644
index 0000000..4fc1926
--- /dev/null
+++ b/lib/api/api.rb
@@ -0,0 +1,28 @@
+Dir["#{Rails.root}/lib/api/*.rb"].each {|file| require file}
+
+module API
+ class API < Grape::API
+ version 'v1', using: :path
+
+ rescue_from ActiveRecord::RecordNotFound do
+ rack_response({'message' => '404 Not found'}.to_json, 404)
+ end
+
+ rescue_from :all do |exception|
+ # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
+ # why is this not wrapped in something reusable?
+ trace = exception.backtrace
+
+ message = "\n#{exception.class} (#{exception.message}):\n"
+ message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
+ message << " " << trace.join("\n ")
+
+ API.logger.add Logger::FATAL, message
+ rack_response({'message' => '500 Internal Server Error'}, 500)
+ end
+
+ format :json
+ helpers Helpers
+ mount Builds
+ end
+end
diff --git a/lib/api/builds.rb b/lib/api/builds.rb
new file mode 100644
index 0000000..2c77001
--- /dev/null
+++ b/lib/api/builds.rb
@@ -0,0 +1,45 @@
+module API
+ # Issues API
+ class Builds < Grape::API
+ resource :builds do
+ # Register a build by runner
+ #
+ # Parameters:
+ # token (required) - The uniq token of runner
+ #
+ # Example Request:
+ # POST /builds/register
+ post "register" do
+ required_attributes! [:token]
+
+ ActiveRecord::Base.transaction do
+ build = Build.pending.order('created_at ASC').first
+ not_found! and return unless build
+
+ build.run!
+ present build, with: Entities::Build
+ end
+ end
+
+ # Update an existing build
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # state (optional) - The state of a build
+ # output (optional) - The trace of a build
+ # Example Request:
+ # PUT /builds/:id
+ put ":id" do
+ build = Build.find(params[:id])
+ build.update_attributes trace: params[:trace]
+
+ case params[:state].to_s
+ when 'success'
+ build.success
+ when 'failed'
+ build.drop
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
new file mode 100644
index 0000000..fdbc29b
--- /dev/null
+++ b/lib/api/entities.rb
@@ -0,0 +1,7 @@
+module API
+ module Entities
+ class Build < Grape::Entity
+ expose :id, :commands, :path, :ref, :sha
+ end
+ end
+end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
new file mode 100644
index 0000000..4448227
--- /dev/null
+++ b/lib/api/helpers.rb
@@ -0,0 +1,104 @@
+module API
+ module Helpers
+ def current_user
+ @current_user ||= User.find_by_authentication_token(params[:private_token] || env["HTTP_PRIVATE_TOKEN"])
+ end
+
+ def user_project
+ @project ||= find_project
+ @project || not_found!
+ end
+
+ def find_project
+ project = Project.find_by_id(params[:id]) || Project.find_with_namespace(params[:id])
+
+ if project && can?(current_user, :read_project, project)
+ project
+ else
+ nil
+ end
+ end
+
+ def paginate(object)
+ object.page(params[:page]).per(params[:per_page].to_i)
+ end
+
+ def authenticate!
+ unauthorized! unless current_user
+ end
+
+ def authenticated_as_admin!
+ forbidden! unless current_user.is_admin?
+ end
+
+ def authorize! action, subject
+ unless abilities.allowed?(current_user, action, subject)
+ forbidden!
+ end
+ end
+
+ def can?(object, action, subject)
+ abilities.allowed?(object, action, subject)
+ end
+
+ # Checks the occurrences of required attributes, each attribute must be present in the params hash
+ # or a Bad Request error is invoked.
+ #
+ # Parameters:
+ # keys (required) - A hash consisting of keys that must be present
+ def required_attributes!(keys)
+ keys.each do |key|
+ bad_request!(key) unless params[key].present?
+ end
+ end
+
+ def attributes_for_keys(keys)
+ attrs = {}
+ keys.each do |key|
+ attrs[key] = params[key] if params[key].present?
+ end
+ attrs
+ end
+
+ # error helpers
+
+ def forbidden!
+ render_api_error!('403 Forbidden', 403)
+ end
+
+ def bad_request!(attribute)
+ message = ["400 (Bad request)"]
+ message << "\"" + attribute.to_s + "\" not given"
+ render_api_error!(message.join(' '), 400)
+ end
+
+ def not_found!(resource = nil)
+ message = ["404"]
+ message << resource if resource
+ message << "Not Found"
+ render_api_error!(message.join(' '), 404)
+ end
+
+ def unauthorized!
+ render_api_error!('401 Unauthorized', 401)
+ end
+
+ def not_allowed!
+ render_api_error!('Method Not Allowed', 405)
+ end
+
+ def render_api_error!(message, status)
+ error!({'message' => message}, status)
+ end
+
+ private
+
+ def abilities
+ @abilities ||= begin
+ abilities = Six.new
+ abilities << Ability
+ abilities
+ end
+ end
+ end
+end