diff options
Diffstat (limited to 'lib/ci')
-rw-r--r-- | lib/ci/ansi2html.rb | 8 | ||||
-rw-r--r-- | lib/ci/api/builds.rb | 14 | ||||
-rw-r--r-- | lib/ci/api/entities.rb | 16 | ||||
-rw-r--r-- | lib/ci/api/helpers.rb | 3 | ||||
-rw-r--r-- | lib/ci/api/triggers.rb | 11 | ||||
-rw-r--r-- | lib/ci/charts.rb | 34 | ||||
-rw-r--r-- | lib/ci/gitlab_ci_yaml_processor.rb | 68 |
7 files changed, 98 insertions, 56 deletions
diff --git a/lib/ci/ansi2html.rb b/lib/ci/ansi2html.rb index b439b0ee29b..b9e9f9f7f4a 100644 --- a/lib/ci/ansi2html.rb +++ b/lib/ci/ansi2html.rb @@ -20,7 +20,7 @@ module Ci italic: 0x02, underline: 0x04, conceal: 0x08, - cross: 0x10, + cross: 0x10 }.freeze def self.convert(ansi, state = nil) @@ -208,7 +208,7 @@ module Ci return unless command = stack.shift() if self.respond_to?("on_#{command}", true) - self.send("on_#{command}", stack) + self.__send__("on_#{command}", stack) # rubocop:disable GitlabSecurity/PublicSend end evaluate_command_stack(stack) @@ -254,7 +254,7 @@ module Ci def state state = STATE_PARAMS.inject({}) do |h, param| - h[param] = send(param) + h[param] = send(param) # rubocop:disable GitlabSecurity/PublicSend h end Base64.urlsafe_encode64(state.to_json) @@ -266,7 +266,7 @@ module Ci return if state[:offset].to_i > stream.size STATE_PARAMS.each do |param| - send("#{param}=".to_sym, state[param]) + send("#{param}=".to_sym, state[param]) # rubocop:disable GitlabSecurity/PublicSend end end diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index 67b269b330c..79058c02ce5 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -29,7 +29,7 @@ module Ci if result.valid? if result.build Gitlab::Metrics.add_event(:build_found, - project: result.build.project.path_with_namespace) + project: result.build.project.full_path) present result.build, with: Entities::BuildDetails else @@ -64,7 +64,7 @@ module Ci build.trace.set(params[:trace]) if params[:trace] Gitlab::Metrics.add_event(:update_build, - project: build.project.path_with_namespace) + project: build.project.full_path) case params[:state].to_s when 'success' @@ -88,7 +88,7 @@ module Ci patch ":id/trace.txt" do build = authenticate_build! - error!('400 Missing header Content-Range', 400) unless request.headers.has_key?('Content-Range') + error!('400 Missing header Content-Range', 400) unless request.headers.key?('Content-Range') content_range = request.headers['Content-Range'] content_range = content_range.split('-') @@ -187,14 +187,14 @@ module Ci build = authenticate_build! artifacts_file = build.artifacts_file - unless artifacts_file.file_storage? - return redirect_to build.artifacts_file.url - end - unless artifacts_file.exists? not_found! end + unless artifacts_file.file_storage? + return redirect_to build.artifacts_file.url + end + present_file!(artifacts_file.path, artifacts_file.filename) end diff --git a/lib/ci/api/entities.rb b/lib/ci/api/entities.rb index 792ff628b09..31f66dd5a58 100644 --- a/lib/ci/api/entities.rb +++ b/lib/ci/api/entities.rb @@ -45,7 +45,21 @@ module Ci expose :artifacts_expire_at, if: ->(build, _) { build.artifacts? } expose :options do |model| - model.options + # This part ensures that output of old API is still the same after adding support + # for extended docker configuration options, used by new API + # + # I'm leaving this here, not in the model, because it should be removed at the same time + # when old API will be removed (planned for August 2017). + model.options.dup.tap do |options| + options[:image] = options[:image][:name] if options[:image].is_a?(Hash) + options[:services]&.map! do |service| + if service.is_a?(Hash) + service[:name] + else + service + end + end + end end expose :timeout do |model| diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb index 5109dc9670f..a40b6ab6c9f 100644 --- a/lib/ci/api/helpers.rb +++ b/lib/ci/api/helpers.rb @@ -28,7 +28,8 @@ module Ci yield if block_given? - forbidden!('Project has been deleted!') unless build.project + project = build.project + forbidden!('Project has been deleted!') if project.nil? || project.pending_delete? forbidden!('Build has been erased!') if build.erased? end diff --git a/lib/ci/api/triggers.rb b/lib/ci/api/triggers.rb index 6e622601680..6225203f223 100644 --- a/lib/ci/api/triggers.rb +++ b/lib/ci/api/triggers.rb @@ -24,12 +24,13 @@ module Ci end # create request and trigger builds - trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref], variables) - if trigger_request - present trigger_request, with: Entities::TriggerRequest + result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref], variables) + pipeline = result.pipeline + + if pipeline.persisted? + present result.trigger_request, with: Entities::TriggerRequest else - errors = 'No builds created' - render_api_error!(errors, 400) + render_validation_error!(pipeline) end end end diff --git a/lib/ci/charts.rb b/lib/ci/charts.rb index 3decc3b1a26..76a69bf8a83 100644 --- a/lib/ci/charts.rb +++ b/lib/ci/charts.rb @@ -2,10 +2,10 @@ module Ci module Charts module DailyInterval def grouped_count(query) - query. - group("DATE(#{Ci::Build.table_name}.created_at)"). - count(:created_at). - transform_keys { |date| date.strftime(@format) } + query + .group("DATE(#{Ci::Pipeline.table_name}.created_at)") + .count(:created_at) + .transform_keys { |date| date.strftime(@format) } end def interval_step @@ -16,14 +16,14 @@ module Ci module MonthlyInterval def grouped_count(query) if Gitlab::Database.postgresql? - query. - group("to_char(#{Ci::Build.table_name}.created_at, '01 Month YYYY')"). - count(:created_at). - transform_keys(&:squish) + query + .group("to_char(#{Ci::Pipeline.table_name}.created_at, '01 Month YYYY')") + .count(:created_at) + .transform_keys(&:squish) else - query. - group("DATE_FORMAT(#{Ci::Build.table_name}.created_at, '01 %M %Y')"). - count(:created_at) + query + .group("DATE_FORMAT(#{Ci::Pipeline.table_name}.created_at, '01 %M %Y')") + .count(:created_at) end end @@ -33,21 +33,21 @@ module Ci end class Chart - attr_reader :labels, :total, :success, :project, :build_times + attr_reader :labels, :total, :success, :project, :pipeline_times def initialize(project) @labels = [] @total = [] @success = [] - @build_times = [] + @pipeline_times = [] @project = project collect end def collect - query = project.builds. - where("? > #{Ci::Build.table_name}.created_at AND #{Ci::Build.table_name}.created_at > ?", @to, @from) + query = project.pipelines + .where("? > #{Ci::Pipeline.table_name}.created_at AND #{Ci::Pipeline.table_name}.created_at > ?", @to, @from) # rubocop:disable GitlabSecurity/SqlInjection totals_count = grouped_count(query) success_count = grouped_count(query.success) @@ -101,14 +101,14 @@ module Ci end end - class BuildTime < Chart + class PipelineTime < Chart def collect commits = project.pipelines.last(30) commits.each do |commit| @labels << commit.short_sha duration = commit.duration || 0 - @build_times << (duration / 60) + @pipeline_times << (duration / 60) end end end diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 15a461a16dd..3a4911b23b0 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -20,26 +20,26 @@ module Ci raise ValidationError, e.message end - def jobs_for_ref(ref, tag = false, trigger_request = nil) + def jobs_for_ref(ref, tag = false, source = nil) @jobs.select do |_, job| - process?(job[:only], job[:except], ref, tag, trigger_request) + process?(job[:only], job[:except], ref, tag, source) end end - def jobs_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil) - jobs_for_ref(ref, tag, trigger_request).select do |_, job| + def jobs_for_stage_and_ref(stage, ref, tag = false, source = nil) + jobs_for_ref(ref, tag, source).select do |_, job| job[:stage] == stage end end - def builds_for_ref(ref, tag = false, trigger_request = nil) - jobs_for_ref(ref, tag, trigger_request).map do |name, _| + def builds_for_ref(ref, tag = false, source = nil) + jobs_for_ref(ref, tag, source).map do |name, _| build_attributes(name) end end - def builds_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil) - jobs_for_stage_and_ref(stage, ref, tag, trigger_request).map do |name, _| + def builds_for_stage_and_ref(stage, ref, tag = false, source = nil) + jobs_for_stage_and_ref(stage, ref, tag, source).map do |name, _| build_attributes(name) end end @@ -50,10 +50,21 @@ module Ci end end + def stage_seeds(pipeline) + seeds = @stages.uniq.map do |stage| + builds = builds_for_stage_and_ref( + stage, pipeline.ref, pipeline.tag?, pipeline.source) + + Gitlab::Ci::Stage::Seed.new(pipeline, stage, builds) if builds.any? + end + + seeds.compact + end + def build_attributes(name) job = @jobs[name.to_sym] || {} - { - stage_idx: @stages.index(job[:stage]), + + { stage_idx: @stages.index(job[:stage]), stage: job[:stage], commands: job[:commands], tag_list: job[:tags] || [], @@ -69,10 +80,12 @@ module Ci artifacts: job[:artifacts], cache: job[:cache], dependencies: job[:dependencies], + before_script: job[:before_script], + script: job[:script], after_script: job[:after_script], environment: job[:environment], - }.compact - } + retry: job[:retry] + }.compact } end def self.validation_message(content) @@ -181,30 +194,35 @@ module Ci end end - def process?(only_params, except_params, ref, tag, trigger_request) + def process?(only_params, except_params, ref, tag, source) if only_params.present? - return false unless matching?(only_params, ref, tag, trigger_request) + return false unless matching?(only_params, ref, tag, source) end if except_params.present? - return false if matching?(except_params, ref, tag, trigger_request) + return false if matching?(except_params, ref, tag, source) end true end - def matching?(patterns, ref, tag, trigger_request) + def matching?(patterns, ref, tag, source) patterns.any? do |pattern| - match_ref?(pattern, ref, tag, trigger_request) + pattern, path = pattern.split('@', 2) + matches_path?(path) && matches_pattern?(pattern, ref, tag, source) end end - def match_ref?(pattern, ref, tag, trigger_request) - pattern, path = pattern.split('@', 2) - return false if path && path != self.path + def matches_path?(path) + return true unless path + + path == self.path + end + + def matches_pattern?(pattern, ref, tag, source) return true if tag && pattern == 'tags' return true if !tag && pattern == 'branches' - return true if trigger_request.present? && pattern == 'triggers' + return true if source_to_pattern(source) == pattern if pattern.first == "/" && pattern.last == "/" Regexp.new(pattern[1...-1]) =~ ref @@ -212,5 +230,13 @@ module Ci pattern == ref end end + + def source_to_pattern(source) + if %w[api external web].include?(source) + source + else + source&.pluralize + end + end end end |