diff options
author | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2013-05-30 16:46:16 +0300 |
---|---|---|
committer | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2013-05-30 16:46:16 +0300 |
commit | 1a595c3f0fb4a80aeb3efdaeb27d084f8029fd57 (patch) | |
tree | 5273c58118dd64c0700a88154eb0c0c7bec59397 /lib | |
parent | d76520a3d091be232ce8a05fcaf605e2f268f821 (diff) | |
download | gitlab-ci-1a595c3f0fb4a80aeb3efdaeb27d084f8029fd57.tar.gz |
Remove runner functionality. Added api for builds
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api/api.rb | 28 | ||||
-rw-r--r-- | lib/api/builds.rb | 45 | ||||
-rw-r--r-- | lib/api/entities.rb | 7 | ||||
-rw-r--r-- | lib/api/helpers.rb | 104 | ||||
-rw-r--r-- | lib/gitlab_ci/encode.rb | 33 | ||||
-rw-r--r-- | lib/runner.rb | 117 | ||||
-rw-r--r-- | lib/scheduler.rb | 3 |
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 |