summaryrefslogtreecommitdiff
path: root/lib
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
parentd76520a3d091be232ce8a05fcaf605e2f268f821 (diff)
downloadgitlab-ci-1a595c3f0fb4a80aeb3efdaeb27d084f8029fd57.tar.gz
Remove runner functionality. Added api for builds
Diffstat (limited to 'lib')
-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
-rw-r--r--lib/gitlab_ci/encode.rb33
-rw-r--r--lib/runner.rb117
-rw-r--r--lib/scheduler.rb3
7 files changed, 184 insertions, 153 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
diff --git a/lib/gitlab_ci/encode.rb b/lib/gitlab_ci/encode.rb
deleted file mode 100644
index 41b8a66..0000000
--- a/lib/gitlab_ci/encode.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require 'charlock_holmes/string'
-
-module GitlabCi
- module Encode
- extend self
-
- def encode!(message)
- return nil unless message.respond_to? :force_encoding
-
- # if message is utf-8 encoding, just return it
- message.force_encoding("UTF-8")
- return message if message.valid_encoding?
-
- # return message if message type is binary
- detect = CharlockHolmes::EncodingDetector.detect(message)
- return message if detect[:type] == :binary
-
- # if message is not utf-8 encoding, convert it
- if detect[:encoding]
- message.force_encoding(detect[:encoding])
- message.encode!("UTF-8", detect[:encoding], undef: :replace, replace: "", invalid: :replace)
- end
-
- # ensure message encoding is utf8
- message.valid_encoding? ? message : raise
-
- # Prevent app from crash cause of encoding errors
- rescue
- encoding = detect ? detect[:encoding] : "unknown"
- "--broken encoding: #{encoding}"
- end
- end
-end
diff --git a/lib/runner.rb b/lib/runner.rb
deleted file mode 100644
index 59e0375..0000000
--- a/lib/runner.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-class Runner
- include Sidekiq::Worker
-
- attr_accessor :project, :build, :output
-
- sidekiq_options queue: :runner
-
- def perform(build_id)
- @build = Build.find(build_id)
- @project = @build.project
- @output = ''
-
- return true if @build.canceled?
-
- run_in_transaction ? run : run_later
- end
-
- def run_in_transaction
- ActiveRecord::Base.transaction do
- build.run! if project.no_running_builds?
- end
- end
-
- def run_later
- Runner.perform_in(2.minutes, @build.id)
- end
-
- def initialize
- @logger = Logger.new(STDOUT)
- @logger.level = Logger::INFO
- end
-
- def run
- path = project.path
- commands = project.scripts
- commands = commands.lines.to_a
- commands.unshift(prepare_project_cmd(path, build.sha))
-
- commands.each do |line|
- status = command(line, path)
- build.write_trace(@output)
-
- return if build.canceled?
-
- unless status
- build.drop!
- return
- end
- end
-
- build.success!
- ensure
- build.write_trace(@output)
- end
-
- def command(cmd, path)
- cmd = cmd.strip
- status = 0
-
- @output ||= ""
- @output << "\n"
- @output << cmd
- @output << "\n"
-
- @process = ChildProcess.build(cmd)
- @tmp_file = Tempfile.new("child-output", binmode: true)
- @process.io.stdout = @tmp_file
- @process.io.stderr = @tmp_file
- @process.cwd = path
-
- # ENV
- @process.environment['BUNDLE_GEMFILE'] = File.join(path, 'Gemfile')
- @process.environment['BUNDLE_BIN_PATH'] = ''
- @process.environment['RUBYOPT'] = ''
-
- @process.environment['CI_SERVER'] = 'yes'
- @process.environment['CI_SERVER_NAME'] = 'GitLab CI'
- @process.environment['CI_SERVER_VERSION'] = GitlabCi::Version
- @process.environment['CI_SERVER_REVISION'] = GitlabCi::Revision
-
- @process.environment['CI_BUILD_REF'] = build.ref
-
- @process.start
-
- build.set_file @tmp_file.path
-
- begin
- @process.poll_for_exit(project.timeout)
- rescue ChildProcess::TimeoutError
- @output << "TIMEOUT"
- @process.stop # tries increasingly harsher methods to kill the process.
- return false
- end
-
- @process.exit_code == 0
-
- rescue => e
- # return false if any exception occurs
- @output << e.message
- false
-
- ensure
- @tmp_file.rewind
- @output << GitlabCi::Encode.encode!(@tmp_file.read)
- @tmp_file.close
- @tmp_file.unlink
- end
-
- def prepare_project_cmd(path, ref)
- cmd = []
- cmd << "cd #{path}"
- cmd << "git fetch"
- cmd << "git reset --hard"
- cmd << "git checkout #{ref}"
- cmd.join(" && ")
- end
-end
diff --git a/lib/scheduler.rb b/lib/scheduler.rb
index ec4ed2c..0418df0 100644
--- a/lib/scheduler.rb
+++ b/lib/scheduler.rb
@@ -6,9 +6,6 @@ class Scheduler
interval = project.polling_interval
if (last_build_time + interval.hours) < Time.now
build = project.register_build(ref: project.tracked_refs.first)
- if build and build.id
- Runner.perform_async(build.id)
- end
end
end
end