diff options
Diffstat (limited to 'lib/gitlab/ci')
53 files changed, 780 insertions, 204 deletions
diff --git a/lib/gitlab/ci/build/releaser.rb b/lib/gitlab/ci/build/releaser.rb index ba6c7857e96..facb5f619bd 100644 --- a/lib/gitlab/ci/build/releaser.rb +++ b/lib/gitlab/ci/build/releaser.rb @@ -5,6 +5,8 @@ module Gitlab module Build class Releaser BASE_COMMAND = 'release-cli create' + SINGLE_FLAGS = %i[name description tag_name ref released_at].freeze + ARRAY_FLAGS = %i[milestones].freeze attr_reader :config @@ -14,9 +16,20 @@ module Gitlab def script command = BASE_COMMAND.dup - config.each { |k, v| command.concat(" --#{k.to_s.dasherize} \"#{v}\"") } + single_flags.each { |k, v| command.concat(" --#{k.to_s.dasherize} \"#{v}\"") } + array_commands.each { |k, v| v.each { |elem| command.concat(" --#{k.to_s.singularize.dasherize} \"#{elem}\"") } } - command + [command] + end + + private + + def single_flags + config.slice(*SINGLE_FLAGS) + end + + def array_commands + config.slice(*ARRAY_FLAGS) end end end diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb index 10e0f4b8e4d..d81a3fef1f5 100644 --- a/lib/gitlab/ci/config.rb +++ b/lib/gitlab/ci/config.rb @@ -39,6 +39,10 @@ module Gitlab @root.errors end + def warnings + @root.warnings + end + def to_hash @config end @@ -93,7 +97,7 @@ module Gitlab Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error, @context.sentry_payload) end - # Overriden in EE + # Overridden in EE def rescue_errors RESCUE_ERRORS end diff --git a/lib/gitlab/ci/config/entry/environment.rb b/lib/gitlab/ci/config/entry/environment.rb index fc62cca58ff..64e6d48133f 100644 --- a/lib/gitlab/ci/config/entry/environment.rb +++ b/lib/gitlab/ci/config/entry/environment.rb @@ -44,7 +44,7 @@ module Gitlab validates :action, type: String, - inclusion: { in: %w[start stop], message: 'should be start or stop' }, + inclusion: { in: %w[start stop prepare], message: 'should be start, stop or prepare' }, allow_nil: true validates :on_stop, type: String, allow_nil: true diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb index 66050a7bbe0..a615cab1a80 100644 --- a/lib/gitlab/ci/config/entry/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -15,7 +15,7 @@ module Gitlab allow_failure type when start_in artifacts cache dependencies before_script needs after_script environment coverage retry parallel interruptible timeout - resource_group release].freeze + resource_group release secrets].freeze REQUIRED_BY_NEEDS = %i[stage].freeze @@ -191,3 +191,5 @@ module Gitlab end end end + +::Gitlab::Ci::Config::Entry::Job.prepend_if_ee('::EE::Gitlab::Ci::Config::Entry::Job') diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb index 81211acbec7..b4539475d88 100644 --- a/lib/gitlab/ci/config/entry/processable.rb +++ b/lib/gitlab/ci/config/entry/processable.rb @@ -82,6 +82,10 @@ module Gitlab @entries.delete(:except) unless except_defined? # rubocop:disable Gitlab/ModuleWithInstanceVariables end + if has_rules? && !has_workflow_rules && Gitlab::Ci::Features.raise_job_rules_without_workflow_rules_warning? + add_warning('uses `rules` without defining `workflow:rules`') + end + # inherit root variables @root_variables_value = deps&.variables_value # rubocop:disable Gitlab/ModuleWithInstanceVariables diff --git a/lib/gitlab/ci/config/entry/release.rb b/lib/gitlab/ci/config/entry/release.rb index b4e4c149730..7e504c24ade 100644 --- a/lib/gitlab/ci/config/entry/release.rb +++ b/lib/gitlab/ci/config/entry/release.rb @@ -12,8 +12,9 @@ module Gitlab include ::Gitlab::Config::Entry::Validatable include ::Gitlab::Config::Entry::Attributable - ALLOWED_KEYS = %i[tag_name name description assets].freeze - attributes %i[tag_name name assets].freeze + ALLOWED_KEYS = %i[tag_name name description ref released_at milestones assets].freeze + attributes %i[tag_name name ref milestones assets].freeze + attr_reader :released_at # Attributable description conflicts with # ::Gitlab::Config::Entry::Node.description @@ -29,8 +30,25 @@ module Gitlab validations do validates :config, allowed_keys: ALLOWED_KEYS - validates :tag_name, presence: true + validates :tag_name, type: String, presence: true validates :description, type: String, presence: true + validates :milestones, array_of_strings_or_string: true, allow_blank: true + validate do + next unless config[:released_at] + + begin + @released_at = DateTime.iso8601(config[:released_at]) + rescue ArgumentError + errors.add(:released_at, "must be a valid datetime") + end + end + validate do + next unless config[:ref] + next if Commit.reference_valid?(config[:ref]) + next if Gitlab::GitRefValidator.validate(config[:ref]) + + errors.add(:ref, "must be a valid ref") + end end def value diff --git a/lib/gitlab/ci/config/entry/reports.rb b/lib/gitlab/ci/config/entry/reports.rb index 74736b24d73..0ae65f43723 100644 --- a/lib/gitlab/ci/config/entry/reports.rb +++ b/lib/gitlab/ci/config/entry/reports.rb @@ -13,9 +13,9 @@ module Gitlab ALLOWED_KEYS = %i[junit codequality sast secret_detection dependency_scanning container_scanning - dast performance license_management license_scanning metrics lsif + dast performance browser_performance load_performance license_management license_scanning metrics lsif dotenv cobertura terraform accessibility cluster_applications - requirements].freeze + requirements coverage_fuzzing].freeze attributes ALLOWED_KEYS @@ -25,13 +25,16 @@ module Gitlab with_options allow_nil: true do validates :junit, array_of_strings_or_string: true - validates :codequality, array_of_strings_or_string: true + validates :coverage_fuzzing, array_of_strings_or_string: true + validates :sast, array_of_strings_or_string: true validates :sast, array_of_strings_or_string: true validates :secret_detection, array_of_strings_or_string: true validates :dependency_scanning, array_of_strings_or_string: true validates :container_scanning, array_of_strings_or_string: true validates :dast, array_of_strings_or_string: true validates :performance, array_of_strings_or_string: true + validates :browser_performance, array_of_strings_or_string: true + validates :load_performance, array_of_strings_or_string: true validates :license_management, array_of_strings_or_string: true validates :license_scanning, array_of_strings_or_string: true validates :metrics, array_of_strings_or_string: true diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb index a2eb31369c7..6130baeb9d5 100644 --- a/lib/gitlab/ci/features.rb +++ b/lib/gitlab/ci/features.rb @@ -10,20 +10,12 @@ module Gitlab ::Feature.enabled?(:ci_artifacts_exclude, default_enabled: true) end - def self.ensure_scheduling_type_enabled? - ::Feature.enabled?(:ci_ensure_scheduling_type, default_enabled: true) - end - def self.job_heartbeats_runner?(project) ::Feature.enabled?(:ci_job_heartbeats_runner, project, default_enabled: true) end - def self.instance_level_variables_limit_enabled? - ::Feature.enabled?(:ci_instance_level_variables_limit, default_enabled: true) - end - def self.pipeline_fixed_notifications? - ::Feature.enabled?(:ci_pipeline_fixed_notifications) + ::Feature.enabled?(:ci_pipeline_fixed_notifications, default_enabled: true) end def self.instance_variables_ui_enabled? @@ -38,9 +30,51 @@ module Gitlab ::Feature.enabled?(:ci_atomic_processing, project, default_enabled: true) end + def self.pipeline_latest? + ::Feature.enabled?(:ci_pipeline_latest, default_enabled: true) + end + + def self.pipeline_status_omit_commit_sha_in_cache_key?(project) + Feature.enabled?(:ci_pipeline_status_omit_commit_sha_in_cache_key, project) + end + def self.release_generation_enabled? - ::Feature.enabled?(:ci_release_generation) + ::Feature.enabled?(:ci_release_generation, default_enabled: true) + end + + # Remove in https://gitlab.com/gitlab-org/gitlab/-/issues/224199 + def self.store_pipeline_messages?(project) + ::Feature.enabled?(:ci_store_pipeline_messages, project, default_enabled: true) + end + + # Remove in https://gitlab.com/gitlab-org/gitlab/-/issues/227052 + def self.variables_api_filter_environment_scope? + ::Feature.enabled?(:ci_variables_api_filter_environment_scope, default_enabled: false) + end + + # This FF is only used for development purpose to test that warnings can be + # raised and propagated to the UI. + def self.raise_job_rules_without_workflow_rules_warning? + ::Feature.enabled?(:ci_raise_job_rules_without_workflow_rules_warning) + end + + def self.keep_latest_artifacts_for_ref_enabled?(project) + ::Feature.enabled?(:keep_latest_artifacts_for_ref, project, default_enabled: false) + end + + def self.destroy_only_unlocked_expired_artifacts_enabled? + ::Feature.enabled?(:destroy_only_unlocked_expired_artifacts, default_enabled: false) + end + + def self.bulk_insert_on_create?(project) + ::Feature.enabled?(:ci_bulk_insert_on_create, project, default_enabled: true) + end + + def self.allow_to_create_merge_request_pipelines_in_target_project?(target_project) + ::Feature.enabled?(:ci_allow_to_create_merge_request_pipelines_in_target_project, target_project) end end end end + +::Gitlab::Ci::Features.prepend_if_ee('::EE::Gitlab::Ci::Features') diff --git a/lib/gitlab/ci/parsers/terraform/tfplan.rb b/lib/gitlab/ci/parsers/terraform/tfplan.rb index 19f724b79af..abfbe18e23f 100644 --- a/lib/gitlab/ci/parsers/terraform/tfplan.rb +++ b/lib/gitlab/ci/parsers/terraform/tfplan.rb @@ -8,15 +8,21 @@ module Gitlab TfplanParserError = Class.new(Gitlab::Ci::Parsers::ParserError) def parse!(json_data, terraform_reports, artifact:) + job_details = job_details(artifact.job) + job_id = job_details['job_id'] plan_data = Gitlab::Json.parse(json_data) - raise TfplanParserError, 'Tfplan missing required key' unless has_required_keys?(plan_data) - - terraform_reports.add_plan(artifact.job.id.to_s, tfplan(plan_data, artifact.job)) + if has_required_keys?(plan_data) + terraform_reports.add_plan(job_id, valid_tfplan(plan_data, job_details)) + else + terraform_reports.add_plan(job_id, invalid_tfplan(:missing_json_keys, job_details)) + end rescue JSON::ParserError - raise TfplanParserError, 'JSON parsing failed' + terraform_reports.add_plan(job_id, invalid_tfplan(:invalid_json_format, job_details)) rescue - raise TfplanParserError, 'Tfplan parsing failed' + details = job_details || {} + plan_name = job_id || 'failed_tf_plan' + terraform_reports.add_plan(plan_name, invalid_tfplan(:unknown_error, details)) end private @@ -25,14 +31,24 @@ module Gitlab (%w[create update delete] - plan_data.keys).empty? end - def tfplan(plan_data, artifact_job) + def job_details(job) { + 'job_id' => job.id.to_s, + 'job_name' => job.options.dig(:artifacts, :name).to_s, + 'job_path' => Gitlab::Routing.url_helpers.project_job_path(job.project, job) + } + end + + def invalid_tfplan(error_type, job_details) + job_details.merge('tf_report_error' => error_type) + end + + def valid_tfplan(plan_data, job_details) + job_details.merge( 'create' => plan_data['create'].to_i, 'delete' => plan_data['delete'].to_i, - 'job_name' => artifact_job.options.dig(:artifacts, :name).to_s, - 'job_path' => Gitlab::Routing.url_helpers.project_job_path(artifact_job.project, artifact_job), 'update' => plan_data['update'].to_i - } + ) end end end diff --git a/lib/gitlab/ci/pipeline/chain/build.rb b/lib/gitlab/ci/pipeline/chain/build.rb index 9662209f88e..4190c40eb66 100644 --- a/lib/gitlab/ci/pipeline/chain/build.rb +++ b/lib/gitlab/ci/pipeline/chain/build.rb @@ -20,7 +20,11 @@ module Gitlab pipeline_schedule: @command.schedule, merge_request: @command.merge_request, external_pull_request: @command.external_pull_request, - variables_attributes: Array(@command.variables_attributes) + variables_attributes: Array(@command.variables_attributes), + # This should be removed and set on the database column default + # level when the keep_latest_artifacts_for_ref feature flag is + # removed. + locked: ::Gitlab::Ci::Features.keep_latest_artifacts_for_ref_enabled?(@command.project) ? :artifacts_locked : :unlocked ) end diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb index 8118e7b2487..74b28b181bc 100644 --- a/lib/gitlab/ci/pipeline/chain/command.rb +++ b/lib/gitlab/ci/pipeline/chain/command.rb @@ -10,7 +10,7 @@ module Gitlab :trigger_request, :schedule, :merge_request, :external_pull_request, :ignore_skip_ci, :save_incompleted, :seeds_block, :variables_attributes, :push_options, - :chat_data, :allow_mirror_update, :bridge, + :chat_data, :allow_mirror_update, :bridge, :content, # These attributes are set by Chains during processing: :config_content, :config_processor, :stage_seeds ) do @@ -78,7 +78,7 @@ module Gitlab end def metrics - @metrics ||= Chain::Metrics.new + @metrics ||= ::Gitlab::Ci::Pipeline::Metrics.new end def observe_creation_duration(duration) @@ -90,6 +90,10 @@ module Gitlab metrics.pipeline_size_histogram .observe({ source: pipeline.source.to_s }, pipeline.total_size) end + + def dangling_build? + %i[ondemand_dast_scan webide].include?(source) + end end end end diff --git a/lib/gitlab/ci/pipeline/chain/config/content.rb b/lib/gitlab/ci/pipeline/chain/config/content.rb index 2008010b523..5314fd471c3 100644 --- a/lib/gitlab/ci/pipeline/chain/config/content.rb +++ b/lib/gitlab/ci/pipeline/chain/config/content.rb @@ -9,6 +9,7 @@ module Gitlab include Chain::Helpers SOURCES = [ + Gitlab::Ci::Pipeline::Chain::Config::Content::Parameter, Gitlab::Ci::Pipeline::Chain::Config::Content::Bridge, Gitlab::Ci::Pipeline::Chain::Config::Content::Repository, Gitlab::Ci::Pipeline::Chain::Config::Content::ExternalProject, diff --git a/lib/gitlab/ci/pipeline/chain/config/content/parameter.rb b/lib/gitlab/ci/pipeline/chain/config/content/parameter.rb new file mode 100644 index 00000000000..3dd216b33d1 --- /dev/null +++ b/lib/gitlab/ci/pipeline/chain/config/content/parameter.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Pipeline + module Chain + module Config + class Content + class Parameter < Source + UnsupportedSourceError = Class.new(StandardError) + + def content + strong_memoize(:content) do + next unless command.content.present? + raise UnsupportedSourceError, "#{command.source} not a dangling build" unless command.dangling_build? + + command.content + end + end + + def source + :parameter_source + end + end + end + end + end + end + end +end diff --git a/lib/gitlab/ci/pipeline/chain/config/content/source.rb b/lib/gitlab/ci/pipeline/chain/config/content/source.rb index 3389187473b..8bc172f93d3 100644 --- a/lib/gitlab/ci/pipeline/chain/config/content/source.rb +++ b/lib/gitlab/ci/pipeline/chain/config/content/source.rb @@ -11,6 +11,8 @@ module Gitlab DEFAULT_YAML_FILE = '.gitlab-ci.yml' + attr_reader :command + def initialize(pipeline, command) @pipeline = pipeline @command = command diff --git a/lib/gitlab/ci/pipeline/chain/config/process.rb b/lib/gitlab/ci/pipeline/chain/config/process.rb index 1e47be21b93..2cfcb295407 100644 --- a/lib/gitlab/ci/pipeline/chain/config/process.rb +++ b/lib/gitlab/ci/pipeline/chain/config/process.rb @@ -19,7 +19,11 @@ module Gitlab parent_pipeline: parent_pipeline } ) + + add_warnings_to_pipeline(@command.config_processor.warnings) rescue Gitlab::Ci::YamlProcessor::ValidationError => ex + add_warnings_to_pipeline(ex.warnings) + error(ex.message, config_error: true) rescue => ex Gitlab::ErrorTracking.track_exception(ex, @@ -34,6 +38,14 @@ module Gitlab def break? @pipeline.errors.any? || @pipeline.persisted? end + + private + + def add_warnings_to_pipeline(warnings) + return unless warnings.present? + + warnings.each { |message| warning(message) } + end end end end diff --git a/lib/gitlab/ci/pipeline/chain/create.rb b/lib/gitlab/ci/pipeline/chain/create.rb index aa627bdb009..34649fe16f3 100644 --- a/lib/gitlab/ci/pipeline/chain/create.rb +++ b/lib/gitlab/ci/pipeline/chain/create.rb @@ -8,7 +8,9 @@ module Gitlab include Chain::Helpers def perform! - pipeline.save! + BulkInsertableAssociations.with_bulk_insert(enabled: ::Gitlab::Ci::Features.bulk_insert_on_create?(project)) do + pipeline.save! + end rescue ActiveRecord::RecordInvalid => e error("Failed to persist the pipeline: #{e}") end diff --git a/lib/gitlab/ci/pipeline/chain/helpers.rb b/lib/gitlab/ci/pipeline/chain/helpers.rb index 982ecc0ff51..aba7dab508d 100644 --- a/lib/gitlab/ci/pipeline/chain/helpers.rb +++ b/lib/gitlab/ci/pipeline/chain/helpers.rb @@ -11,9 +11,18 @@ module Gitlab pipeline.yaml_errors = message end + pipeline.add_error_message(message) pipeline.drop!(drop_reason) if drop_reason + + # TODO: consider not to rely on AR errors directly as they can be + # polluted with other unrelated errors (e.g. state machine) + # https://gitlab.com/gitlab-org/gitlab/-/issues/220823 pipeline.errors.add(:base, message) end + + def warning(message) + pipeline.add_warning_message(message) + end end end end diff --git a/lib/gitlab/ci/pipeline/chain/metrics.rb b/lib/gitlab/ci/pipeline/chain/metrics.rb deleted file mode 100644 index 980ab2de9b0..00000000000 --- a/lib/gitlab/ci/pipeline/chain/metrics.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Ci - module Pipeline - module Chain - class Metrics - include Gitlab::Utils::StrongMemoize - - def pipeline_creation_duration_histogram - strong_memoize(:pipeline_creation_duration_histogram) do - name = :gitlab_ci_pipeline_creation_duration_seconds - comment = 'Pipeline creation duration' - labels = {} - buckets = [0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 5.0, 20.0, 50.0, 240.0] - - ::Gitlab::Metrics.histogram(name, comment, labels, buckets) - end - end - - def pipeline_size_histogram - strong_memoize(:pipeline_size_histogram) do - name = :gitlab_ci_pipeline_size_builds - comment = 'Pipeline size' - labels = { source: nil } - buckets = [0, 1, 5, 10, 20, 50, 100, 200, 500, 1000] - - ::Gitlab::Metrics.histogram(name, comment, labels, buckets) - end - end - end - end - end - end -end diff --git a/lib/gitlab/ci/pipeline/chain/validate/abilities.rb b/lib/gitlab/ci/pipeline/chain/validate/abilities.rb index a30b6c6ef0e..769d0dffd0b 100644 --- a/lib/gitlab/ci/pipeline/chain/validate/abilities.rb +++ b/lib/gitlab/ci/pipeline/chain/validate/abilities.rb @@ -19,7 +19,7 @@ module Gitlab end unless allowed_to_write_ref? - return error("Insufficient permissions for protected ref '#{command.ref}'") + error("Insufficient permissions for protected ref '#{command.ref}'") end end diff --git a/lib/gitlab/ci/pipeline/chain/validate/repository.rb b/lib/gitlab/ci/pipeline/chain/validate/repository.rb index 8f5445850d7..7977ce90443 100644 --- a/lib/gitlab/ci/pipeline/chain/validate/repository.rb +++ b/lib/gitlab/ci/pipeline/chain/validate/repository.rb @@ -18,7 +18,7 @@ module Gitlab end if @command.ambiguous_ref? - return error('Ref is ambiguous') + error('Ref is ambiguous') end end diff --git a/lib/gitlab/ci/pipeline/metrics.rb b/lib/gitlab/ci/pipeline/metrics.rb new file mode 100644 index 00000000000..649da745eea --- /dev/null +++ b/lib/gitlab/ci/pipeline/metrics.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Pipeline + class Metrics + include Gitlab::Utils::StrongMemoize + + def pipeline_creation_duration_histogram + strong_memoize(:pipeline_creation_duration_histogram) do + name = :gitlab_ci_pipeline_creation_duration_seconds + comment = 'Pipeline creation duration' + labels = {} + buckets = [0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 5.0, 20.0, 50.0, 240.0] + + ::Gitlab::Metrics.histogram(name, comment, labels, buckets) + end + end + + def pipeline_size_histogram + strong_memoize(:pipeline_size_histogram) do + name = :gitlab_ci_pipeline_size_builds + comment = 'Pipeline size' + labels = { source: nil } + buckets = [0, 1, 5, 10, 20, 50, 100, 200, 500, 1000] + + ::Gitlab::Metrics.histogram(name, comment, labels, buckets) + end + end + + def pipeline_processing_events_counter + strong_memoize(:pipeline_processing_events_counter) do + name = :gitlab_ci_pipeline_processing_events_total + comment = 'Total amount of pipeline processing events' + + Gitlab::Metrics.counter(name, comment) + end + end + end + end + end +end diff --git a/lib/gitlab/ci/pipeline/preloader.rb b/lib/gitlab/ci/pipeline/preloader.rb index db0a1ea4dab..7befc126ca9 100644 --- a/lib/gitlab/ci/pipeline/preloader.rb +++ b/lib/gitlab/ci/pipeline/preloader.rb @@ -17,6 +17,7 @@ module Gitlab pipelines.each do |pipeline| self.new(pipeline).tap do |preloader| preloader.preload_commit_authors + preloader.preload_ref_commits preloader.preload_pipeline_warnings preloader.preload_stages_warnings end @@ -27,12 +28,19 @@ module Gitlab @pipeline = pipeline end + # This also preloads the author of every commit. We're using "lazy_author" + # here since "author" immediately loads the data on the first call. def preload_commit_authors - # This also preloads the author of every commit. We're using "lazy_author" - # here since "author" immediately loads the data on the first call. @pipeline.commit.try(:lazy_author) end + # This preloads latest commits for given refs and therefore makes it + # much less expensive to check if a pipeline is a latest one for + # given branch. + def preload_ref_commits + @pipeline.lazy_ref_commit + end + def preload_pipeline_warnings # This preloads the number of warnings for every pipeline, ensuring # that Ci::Pipeline#has_warnings? doesn't execute any additional @@ -40,10 +48,10 @@ module Gitlab @pipeline.number_of_warnings end + # This preloads the number of warnings for every stage, ensuring + # that Ci::Stage#has_warnings? doesn't execute any additional + # queries. def preload_stages_warnings - # This preloads the number of warnings for every stage, ensuring - # that Ci::Stage#has_warnings? doesn't execute any additional - # queries. @pipeline.stages.each { |stage| stage.number_of_warnings } end end diff --git a/lib/gitlab/ci/reports/test_report_summary.rb b/lib/gitlab/ci/reports/test_report_summary.rb new file mode 100644 index 00000000000..85b83b790e7 --- /dev/null +++ b/lib/gitlab/ci/reports/test_report_summary.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Reports + class TestReportSummary + attr_reader :all_results + + def initialize(all_results) + @all_results = all_results + end + + def total + TestSuiteSummary.new(all_results) + end + + def total_time + total.total_time + end + + def total_count + total.total_count + end + + def success_count + total.success_count + end + + def failed_count + total.failed_count + end + + def skipped_count + total.skipped_count + end + + def error_count + total.error_count + end + + def test_suites + all_results + .group_by(&:tests_name) + .transform_values { |results| TestSuiteSummary.new(results) } + end + end + end + end +end diff --git a/lib/gitlab/ci/reports/test_suite.rb b/lib/gitlab/ci/reports/test_suite.rb index 8bbf2e0f6cf..28b81e7a471 100644 --- a/lib/gitlab/ci/reports/test_suite.rb +++ b/lib/gitlab/ci/reports/test_suite.rb @@ -4,9 +4,9 @@ module Gitlab module Ci module Reports class TestSuite - attr_reader :name - attr_reader :test_cases - attr_reader :total_time + attr_accessor :name + attr_accessor :test_cases + attr_accessor :total_time attr_reader :suite_error def initialize(name = nil) @@ -70,6 +70,14 @@ module Gitlab @suite_error = msg end + def +(other) + self.class.new.tap do |test_suite| + test_suite.name = self.name + test_suite.test_cases = self.test_cases.deep_merge(other.test_cases) + test_suite.total_time = self.total_time + other.total_time + end + end + private def existing_key?(test_case) diff --git a/lib/gitlab/ci/reports/test_suite_summary.rb b/lib/gitlab/ci/reports/test_suite_summary.rb new file mode 100644 index 00000000000..f9b0bedb712 --- /dev/null +++ b/lib/gitlab/ci/reports/test_suite_summary.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Reports + class TestSuiteSummary + attr_reader :results + + def initialize(results) + @results = results + end + + def name + @name ||= results.first.tests_name + end + + # rubocop: disable CodeReuse/ActiveRecord + def build_ids + results.pluck(:build_id) + end + + def total_time + @total_time ||= results.sum(&:tests_duration) + end + + def success_count + @success_count ||= results.sum(&:tests_success) + end + + def failed_count + @failed_count ||= results.sum(&:tests_failed) + end + + def skipped_count + @skipped_count ||= results.sum(&:tests_skipped) + end + + def error_count + @error_count ||= results.sum(&:tests_errored) + end + + def total_count + @total_count ||= [success_count, failed_count, skipped_count, error_count].sum + end + # rubocop: disable CodeReuse/ActiveRecord + end + end + end +end diff --git a/lib/gitlab/ci/status/composite.rb b/lib/gitlab/ci/status/composite.rb index 074651f1040..04a9fc29802 100644 --- a/lib/gitlab/ci/status/composite.rb +++ b/lib/gitlab/ci/status/composite.rb @@ -112,13 +112,13 @@ module Gitlab def success_with_warnings?(status) @allow_failure_key && status[@allow_failure_key] && - HasStatus::PASSED_WITH_WARNINGS_STATUSES.include?(status[@status_key]) + ::Ci::HasStatus::PASSED_WITH_WARNINGS_STATUSES.include?(status[@status_key]) end def ignored_status?(status) @allow_failure_key && status[@allow_failure_key] && - HasStatus::EXCLUDE_IGNORED_STATUSES.include?(status[@status_key]) + ::Ci::HasStatus::EXCLUDE_IGNORED_STATUSES.include?(status[@status_key]) end end end diff --git a/lib/gitlab/ci/status/factory.rb b/lib/gitlab/ci/status/factory.rb index 73c73a3b3fc..4a384531c57 100644 --- a/lib/gitlab/ci/status/factory.rb +++ b/lib/gitlab/ci/status/factory.rb @@ -7,7 +7,7 @@ module Gitlab def initialize(subject, user) @subject = subject @user = user - @status = subject.status || HasStatus::DEFAULT_STATUS + @status = subject.status || ::Ci::HasStatus::DEFAULT_STATUS end def fabricate! diff --git a/lib/gitlab/ci/status/stage/play_manual.rb b/lib/gitlab/ci/status/stage/play_manual.rb index ac3fc0912fa..58859a8f191 100644 --- a/lib/gitlab/ci/status/stage/play_manual.rb +++ b/lib/gitlab/ci/status/stage/play_manual.rb @@ -18,7 +18,7 @@ module Gitlab def action_path pipeline = subject.pipeline - project_stage_play_manual_path(pipeline.project, pipeline, subject.name) + project_pipeline_stage_play_manual_path(pipeline.project, pipeline, subject.name) end def action_method diff --git a/lib/gitlab/ci/templates/Android-Fastlane.gitlab-ci.yml b/lib/gitlab/ci/templates/Android-Fastlane.gitlab-ci.yml index be584814271..5ebbbf15682 100644 --- a/lib/gitlab/ci/templates/Android-Fastlane.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Android-Fastlane.gitlab-ci.yml @@ -20,7 +20,7 @@ stages: - docker:dind script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG || true + - docker pull --quiet $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG || true - docker build --cache-from $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG diff --git a/lib/gitlab/ci/templates/Android.gitlab-ci.yml b/lib/gitlab/ci/templates/Android.gitlab-ci.yml index b7194110002..d20dabc0b00 100644 --- a/lib/gitlab/ci/templates/Android.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Android.gitlab-ci.yml @@ -4,32 +4,65 @@ image: openjdk:8-jdk variables: - ANDROID_COMPILE_SDK: "28" - ANDROID_BUILD_TOOLS: "28.0.2" - ANDROID_SDK_TOOLS: "4333796" + # ANDROID_COMPILE_SDK is the version of Android you're compiling with. + # It should match compileSdkVersion. + ANDROID_COMPILE_SDK: "29" + + # ANDROID_BUILD_TOOLS is the version of the Android build tools you are using. + # It should match buildToolsVersion. + ANDROID_BUILD_TOOLS: "29.0.3" + + # It's what version of the command line tools we're going to download from the official site. + # Official Site-> https://developer.android.com/studio/index.html + # There, look down below at the cli tools only, sdk tools package is of format: + # commandlinetools-os_type-ANDROID_SDK_TOOLS_latest.zip + # when the script was last modified for latest compileSdkVersion, it was which is written down below + ANDROID_SDK_TOOLS: "6514223" + +# Packages installation before running script before_script: - apt-get --quiet update --yes - apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1 - - wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS}.zip - - unzip -d android-sdk-linux android-sdk.zip - - echo y | android-sdk-linux/tools/bin/sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" >/dev/null - - echo y | android-sdk-linux/tools/bin/sdkmanager "platform-tools" >/dev/null - - echo y | android-sdk-linux/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}" >/dev/null - - export ANDROID_HOME=$PWD/android-sdk-linux - - export PATH=$PATH:$PWD/android-sdk-linux/platform-tools/ + + # Setup path as android_home for moving/exporting the downloaded sdk into it + - export ANDROID_HOME="${PWD}/android-home" + # Create a new directory at specified location + - install -d $ANDROID_HOME + # Here we are installing androidSDK tools from official source, + # (the key thing here is the url from where you are downloading these sdk tool for command line, so please do note this url pattern there and here as well) + # after that unzipping those tools and + # then running a series of SDK manager commands to install necessary android SDK packages that'll allow the app to build + - wget --output-document=$ANDROID_HOME/cmdline-tools.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS}_latest.zip + # move to the archive at ANDROID_HOME + - pushd $ANDROID_HOME + - unzip -d cmdline-tools cmdline-tools.zip + - popd + - export PATH=$PATH:${ANDROID_HOME}/cmdline-tools/tools/bin/ + + # Nothing fancy here, just checking sdkManager version + - sdkmanager --version + + # use yes to accept all licenses + - yes | sdkmanager --sdk_root=${ANDROID_HOME} --licenses || true + - sdkmanager --sdk_root=${ANDROID_HOME} "platforms;android-${ANDROID_COMPILE_SDK}" + - sdkmanager --sdk_root=${ANDROID_HOME} "platform-tools" + - sdkmanager --sdk_root=${ANDROID_HOME} "build-tools;${ANDROID_BUILD_TOOLS}" + + # Not necessary, but just for surity - chmod +x ./gradlew - # temporarily disable checking for EPIPE error and use yes to accept all licenses - - set +o pipefail - - yes | android-sdk-linux/tools/bin/sdkmanager --licenses - - set -o pipefail +# Basic android and gradle stuff +# Check linting lintDebug: + interruptible: true stage: build script: - ./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint +# Make Project assembleDebug: + interruptible: true stage: build script: - ./gradlew assembleDebug @@ -37,7 +70,9 @@ assembleDebug: paths: - app/build/outputs/ +# Run all tests, if any fails, interrupt the pipeline(fail it) debugTests: + interruptible: true stage: test script: - ./gradlew -Pci --console=plain :app:testDebug diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml index e37cd14d1d1..c10d87a537b 100644 --- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @@ -12,6 +12,7 @@ # * code_quality: CODE_QUALITY_DISABLED # * license_management: LICENSE_MANAGEMENT_DISABLED # * performance: PERFORMANCE_DISABLED +# * load_performance: LOAD_PERFORMANCE_DISABLED # * sast: SAST_DISABLED # * secret_detection: SECRET_DETECTION_DISABLED # * dependency_scanning: DEPENDENCY_SCANNING_DISABLED @@ -74,7 +75,7 @@ stages: workflow: rules: - - if: '$BUILDPACK_URL || $AUTO_DEVOPS_EXPLICITLY_ENABLED == "1"' + - if: '$BUILDPACK_URL || $AUTO_DEVOPS_EXPLICITLY_ENABLED == "1" || $DOCKERFILE_PATH' - exists: - Dockerfile diff --git a/lib/gitlab/ci/templates/Composer.gitlab-ci.yml b/lib/gitlab/ci/templates/Composer.gitlab-ci.yml new file mode 100644 index 00000000000..5d9c68d3031 --- /dev/null +++ b/lib/gitlab/ci/templates/Composer.gitlab-ci.yml @@ -0,0 +1,19 @@ +# Publishes a tag/branch to Composer Packages of the current project +publish: + image: curlimages/curl:latest + stage: build + variables: + URL: "$CI_SERVER_PROTOCOL://$CI_SERVER_HOST:$CI_SERVER_PORT/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN" + script: + - version=$([[ -z "$CI_COMMIT_TAG" ]] && echo "branch=$CI_COMMIT_REF_NAME" || echo "tag=$CI_COMMIT_TAG") + - insecure=$([ "$CI_SERVER_PROTOCOL" = "http" ] && echo "--insecure" || echo "") + - response=$(curl -s -w "\n%{http_code}" $insecure --data $version $URL) + - code=$(echo "$response" | tail -n 1) + - body=$(echo "$response" | head -n 1) + # Output state information + - if [ $code -eq 201 ]; then + echo "Package created - Code $code - $body"; + else + echo "Could not create package - Code $code - $body"; + exit 1; + fi diff --git a/lib/gitlab/ci/templates/Dart.gitlab-ci.yml b/lib/gitlab/ci/templates/Dart.gitlab-ci.yml new file mode 100644 index 00000000000..cc383f89b0c --- /dev/null +++ b/lib/gitlab/ci/templates/Dart.gitlab-ci.yml @@ -0,0 +1,22 @@ +# https://hub.docker.com/r/google/dart +image: google/dart:2.8.4 + +variables: + # Use to learn more: + # pub run test --help + PUB_VARS: "--platform vm --timeout 30s --concurrency=6 --test-randomize-ordering-seed=random --reporter=expanded" + +# Cache downloaded dependencies and plugins between builds. +# To keep cache across branches add 'key: "$CI_JOB_NAME"' +cache: + paths: + - .pub-cache/global_packages + +before_script: + - export PATH="$PATH":"~/.pub-cache/bin" + - pub get --no-precompile + +test: + stage: test + script: + - pub run test $PUB_VARS diff --git a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml index 9a34f8cb113..8553a940bd7 100644 --- a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml @@ -1,11 +1,16 @@ +# Read more about the feature here: https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html + performance: stage: performance - image: docker:19.03.11 + image: docker:19.03.12 allow_failure: true variables: DOCKER_TLS_CERTDIR: "" + SITESPEED_IMAGE: sitespeedio/sitespeed.io + SITESPEED_VERSION: 13.3.0 + SITESPEED_OPTIONS: '' services: - - docker:19.03.11-dind + - docker:19.03.12-dind script: - | if ! docker info &>/dev/null; then @@ -15,21 +20,22 @@ performance: fi - export CI_ENVIRONMENT_URL=$(cat environment_url.txt) - mkdir gitlab-exporter - - wget -O gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/1.0.0/index.js + - wget -O gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/1.0.1/index.js - mkdir sitespeed-results - | if [ -f .gitlab-urls.txt ] then sed -i -e 's@^@'"$CI_ENVIRONMENT_URL"'@' .gitlab-urls.txt - docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:11.2.0 --plugins.add ./gitlab-exporter --outputFolder sitespeed-results .gitlab-urls.txt + docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io $SITESPEED_IMAGE:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --outputFolder sitespeed-results .gitlab-urls.txt $SITESPEED_OPTIONS else - docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:11.2.0 --plugins.add ./gitlab-exporter --outputFolder sitespeed-results "$CI_ENVIRONMENT_URL" + docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io $SITESPEED_IMAGE:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --outputFolder sitespeed-results "$CI_ENVIRONMENT_URL" $SITESPEED_OPTIONS fi - - mv sitespeed-results/data/performance.json performance.json + - mv sitespeed-results/data/performance.json browser-performance.json artifacts: paths: - - performance.json - sitespeed-results/ + reports: + browser_performance: browser-performance.json rules: - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""' when: never diff --git a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml index b5550461482..dbe870953ae 100644 --- a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml @@ -1,10 +1,10 @@ build: stage: build - image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-build-image:v0.2.3" + image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-build-image:v0.3.1" variables: DOCKER_TLS_CERTDIR: "" services: - - docker:19.03.11-dind + - docker:19.03.12-dind script: - | if [[ -z "$CI_COMMIT_TAG" ]]; then diff --git a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml index bde6f185d3a..6b76d7e0c9b 100644 --- a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml @@ -1,13 +1,14 @@ code_quality: stage: test - image: docker:19.03.11 + image: docker:19.03.12 allow_failure: true services: - - docker:19.03.11-dind + - docker:19.03.12-dind variables: DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "" - CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.9" + CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.10" + needs: [] script: - | if ! docker info &>/dev/null; then diff --git a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml index bab4fae67f0..d7d927ac8ee 100644 --- a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml @@ -1,5 +1,5 @@ .dast-auto-deploy: - image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.17.0" + image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.17.2" dast_environment_deploy: extends: .dast-auto-deploy @@ -51,3 +51,4 @@ stop_dast_environment: - if: $CI_COMMIT_BRANCH && $CI_KUBERNETES_ACTIVE && $GITLAB_FEATURES =~ /\bdast\b/ + when: always diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml index 97b5f3fd7f5..66c60e85892 100644 --- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml @@ -1,5 +1,6 @@ .auto-deploy: - image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.17.0" + image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.17.2" + dependencies: [] include: - template: Jobs/Deploy/ECS.gitlab-ci.yml @@ -20,7 +21,8 @@ review: url: http://$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG.$KUBE_INGRESS_BASE_DOMAIN on_stop: stop_review artifacts: - paths: [environment_url.txt] + paths: [environment_url.txt, tiller.log] + when: always rules: - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""' when: never @@ -41,7 +43,6 @@ stop_review: environment: name: review/$CI_COMMIT_REF_NAME action: stop - dependencies: [] allow_failure: true rules: - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""' @@ -122,7 +123,8 @@ canary: name: production url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN artifacts: - paths: [environment_url.txt] + paths: [environment_url.txt, tiller.log] + when: always production: <<: *production_template @@ -172,7 +174,8 @@ production_manual: name: production url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN artifacts: - paths: [environment_url.txt] + paths: [environment_url.txt, tiller.log] + when: always .manual_rollout_template: &manual_rollout_template <<: *rollout_template diff --git a/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml index bb3d5526f3a..da474f8ac88 100644 --- a/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml @@ -13,11 +13,20 @@ script: - ecs update-task-definition -review_ecs: - extends: .deploy_to_ecs +.review_ecs_base: stage: review + extends: .deploy_to_ecs environment: name: review/$CI_COMMIT_REF_NAME + +.production_ecs_base: + stage: production + extends: .deploy_to_ecs + environment: + name: production + +review_ecs: + extends: .review_ecs_base rules: - if: '$AUTO_DEVOPS_PLATFORM_TARGET != "ECS"' when: never @@ -29,11 +38,21 @@ review_ecs: when: never - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH' +review_fargate: + extends: .review_ecs_base + rules: + - if: '$AUTO_DEVOPS_PLATFORM_TARGET != "FARGATE"' + when: never + - if: '$CI_KUBERNETES_ACTIVE' + when: never + - if: '$REVIEW_DISABLED' + when: never + - if: '$CI_COMMIT_BRANCH == "master"' + when: never + - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH' + production_ecs: - extends: .deploy_to_ecs - stage: production - environment: - name: production + extends: .production_ecs_base rules: - if: '$AUTO_DEVOPS_PLATFORM_TARGET != "ECS"' when: never @@ -42,3 +61,14 @@ production_ecs: - if: '$CI_COMMIT_BRANCH != "master"' when: never - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH' + +production_fargate: + extends: .production_ecs_base + rules: + - if: '$AUTO_DEVOPS_PLATFORM_TARGET != "FARGATE"' + when: never + - if: '$CI_KUBERNETES_ACTIVE' + when: never + - if: '$CI_COMMIT_BRANCH != "master"' + when: never + - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH' diff --git a/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml new file mode 100644 index 00000000000..b437ddbd734 --- /dev/null +++ b/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml @@ -0,0 +1,29 @@ +load_performance: + stage: performance + image: docker:19.03.11 + allow_failure: true + variables: + DOCKER_TLS_CERTDIR: "" + K6_IMAGE: loadimpact/k6 + K6_VERSION: 0.26.2 + K6_TEST_FILE: github.com/loadimpact/k6/samples/http_get.js + K6_OPTIONS: '' + services: + - docker:19.03.11-dind + script: + - | + if ! docker info &>/dev/null; then + if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then + export DOCKER_HOST='tcp://localhost:2375' + fi + fi + - docker run --rm -v "$(pwd)":/k6 -w /k6 $K6_IMAGE:$K6_VERSION run $K6_TEST_FILE --summary-export=load-performance.json $K6_OPTIONS + artifacts: + reports: + load_performance: load-performance.json + rules: + - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""' + when: never + - if: '$LOAD_PERFORMANCE_DISABLED' + when: never + - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH' diff --git a/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml b/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml index 316647b5921..3d0bacda853 100644 --- a/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml @@ -1,6 +1,6 @@ apply: stage: deploy - image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.20.0" + image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.24.2" environment: name: production variables: diff --git a/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml new file mode 100644 index 00000000000..2fab8b95a3d --- /dev/null +++ b/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml @@ -0,0 +1,34 @@ +# Read more about this feature https://docs.gitlab.com/ee/user/application_security/coverage_fuzzing + +variables: + # Which branch we want to run full fledged long running fuzzing jobs. + # All others will run fuzzing regression + COVERAGE_FUZZING_BRANCH: "$CI_DEFAULT_BRANCH" + # This is using semantic version and will always download latest v1 gitlab-cov-fuzz release + COVERAGE_FUZZING_VERSION: v1 + # This is for users who have an offline environment and will have to replicate gitlab-cov-fuzz release binaries + # to their own servers + COVERAGE_FUZZING_URL_PREFIX: "https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-cov-fuzz/-/raw" + +.fuzz_base: + stage: fuzz + allow_failure: true + before_script: + - if [ -x "$(command -v apt-get)" ] ; then apt-get update && apt-get install -y wget; fi + - wget -O gitlab-cov-fuzz "${COVERAGE_FUZZING_URL_PREFIX}"/"${COVERAGE_FUZZING_VERSION}"/binaries/gitlab-cov-fuzz_Linux_x86_64 + - chmod a+x gitlab-cov-fuzz + - export REGRESSION=true + - if [[ $CI_COMMIT_BRANCH = $COVERAGE_FUZZING_BRANCH ]]; then REGRESSION=false; fi; + artifacts: + paths: + - corpus + - crashes + - gl-coverage-fuzzing-report.json + reports: + coverage_fuzzing: gl-coverage-fuzzing-report.json + when: always + rules: + - if: $COVERAGE_FUZZING_DISABLED + when: never + - if: $GITLAB_FEATURES =~ /\bcoverage_fuzzing\b/ + - if: $CI_RUNNER_EXECUTABLE_ARCH == "linux" diff --git a/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml index 07399216597..7abecfb7e49 100644 --- a/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml @@ -41,4 +41,11 @@ dast: $DAST_API_SPECIFICATION == null when: never - if: $CI_COMMIT_BRANCH && + $CI_KUBERNETES_ACTIVE && $GITLAB_FEATURES =~ /\bdast\b/ + - if: $CI_COMMIT_BRANCH && + $GITLAB_FEATURES =~ /\bdast\b/ && + $DAST_WEBSITE + - if: $CI_COMMIT_BRANCH && + $GITLAB_FEATURES =~ /\bdast\b/ && + $DAST_API_SPECIFICATION diff --git a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml index fa8ccb7cf93..37f6cd216ca 100644 --- a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml @@ -9,9 +9,6 @@ variables: # (SAST, Dependency Scanning, ...) SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers" - # Deprecated, use SECURE_ANALYZERS_PREFIX instead - DS_ANALYZER_IMAGE_PREFIX: "$SECURE_ANALYZERS_PREFIX" - DS_DEFAULT_ANALYZERS: "bundler-audit, retire.js, gemnasium, gemnasium-maven, gemnasium-python" DS_EXCLUDED_PATHS: "spec, test, tests, tmp" DS_MAJOR_VERSION: 2 @@ -45,7 +42,7 @@ dependency_scanning: docker run \ $(propagate_env_vars \ DS_ANALYZER_IMAGES \ - DS_ANALYZER_IMAGE_PREFIX \ + SECURE_ANALYZERS_PREFIX \ DS_ANALYZER_IMAGE_TAG \ DS_DEFAULT_ANALYZERS \ DS_EXCLUDED_PATHS \ @@ -55,6 +52,7 @@ dependency_scanning: DS_PYTHON_VERSION \ DS_PIP_VERSION \ DS_PIP_DEPENDENCY_PATH \ + DS_JAVA_VERSION \ GEMNASIUM_DB_LOCAL_PATH \ GEMNASIUM_DB_REMOTE_URL \ GEMNASIUM_DB_REF_NAME \ @@ -98,7 +96,7 @@ dependency_scanning: gemnasium-dependency_scanning: extends: .ds-analyzer image: - name: "$DS_ANALYZER_IMAGE_PREFIX/gemnasium:$DS_MAJOR_VERSION" + name: "$SECURE_ANALYZERS_PREFIX/gemnasium:$DS_MAJOR_VERSION" rules: - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false' when: never @@ -117,7 +115,7 @@ gemnasium-dependency_scanning: gemnasium-maven-dependency_scanning: extends: .ds-analyzer image: - name: "$DS_ANALYZER_IMAGE_PREFIX/gemnasium-maven:$DS_MAJOR_VERSION" + name: "$SECURE_ANALYZERS_PREFIX/gemnasium-maven:$DS_MAJOR_VERSION" rules: - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false' when: never @@ -133,7 +131,7 @@ gemnasium-maven-dependency_scanning: gemnasium-python-dependency_scanning: extends: .ds-analyzer image: - name: "$DS_ANALYZER_IMAGE_PREFIX/gemnasium-python:$DS_MAJOR_VERSION" + name: "$SECURE_ANALYZERS_PREFIX/gemnasium-python:$DS_MAJOR_VERSION" rules: - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false' when: never @@ -156,7 +154,7 @@ gemnasium-python-dependency_scanning: bundler-audit-dependency_scanning: extends: .ds-analyzer image: - name: "$DS_ANALYZER_IMAGE_PREFIX/bundler-audit:$DS_MAJOR_VERSION" + name: "$SECURE_ANALYZERS_PREFIX/bundler-audit:$DS_MAJOR_VERSION" rules: - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false' when: never @@ -169,7 +167,7 @@ bundler-audit-dependency_scanning: retire-js-dependency_scanning: extends: .ds-analyzer image: - name: "$DS_ANALYZER_IMAGE_PREFIX/retire.js:$DS_MAJOR_VERSION" + name: "$SECURE_ANALYZERS_PREFIX/retire.js:$DS_MAJOR_VERSION" rules: - if: $DEPENDENCY_SCANNING_DISABLED || $DS_DISABLE_DIND == 'false' when: never diff --git a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml index b0c75b0aab0..cc34d23decc 100644 --- a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml @@ -18,15 +18,15 @@ license_scanning: name: "$SECURE_ANALYZERS_PREFIX/license-finder:$LICENSE_MANAGEMENT_VERSION" entrypoint: [""] variables: - LM_REPORT_FILE: gl-license-scanning-report.json LM_REPORT_VERSION: '2.1' SETUP_CMD: $LICENSE_MANAGEMENT_SETUP_CMD allow_failure: true + needs: [] script: - /run.sh analyze . artifacts: reports: - license_scanning: $LM_REPORT_FILE + license_scanning: gl-license-scanning-report.json dependencies: [] rules: - if: $LICENSE_MANAGEMENT_DISABLED diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml index ec7b34d17b5..f0e2f48dd5c 100644 --- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml @@ -9,10 +9,7 @@ variables: # (SAST, Dependency Scanning, ...) SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers" - # Deprecated, use SECURE_ANALYZERS_PREFIX instead - SAST_ANALYZER_IMAGE_PREFIX: "$SECURE_ANALYZERS_PREFIX" - - SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, tslint, secrets, sobelow, pmd-apex, kubesec" + SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, secrets, sobelow, pmd-apex, kubesec" SAST_EXCLUDED_PATHS: "spec, test, tests, tmp" SAST_ANALYZER_IMAGE_TAG: 2 SAST_DISABLE_DIND: "true" @@ -63,7 +60,7 @@ sast: bandit-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/bandit:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/bandit:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -76,7 +73,7 @@ bandit-sast: brakeman-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/brakeman:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/brakeman:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -88,21 +85,23 @@ brakeman-sast: eslint-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/eslint:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/eslint:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never - if: $CI_COMMIT_BRANCH && - $GITLAB_FEATURES =~ /\bsast\b/ && $SAST_DEFAULT_ANALYZERS =~ /eslint/ exists: - '**/*.html' - '**/*.js' + - '**/*.jsx' + - '**/*.ts' + - '**/*.tsx' flawfinder-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/flawfinder:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/flawfinder:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -116,7 +115,7 @@ flawfinder-sast: kubesec-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/kubesec:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/kubesec:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -128,7 +127,7 @@ kubesec-sast: gosec-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/gosec:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/gosec:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -141,7 +140,7 @@ gosec-sast: nodejs-scan-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/nodejs-scan:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/nodejs-scan:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -154,7 +153,7 @@ nodejs-scan-sast: phpcs-security-audit-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/phpcs-security-audit:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/phpcs-security-audit:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -167,7 +166,7 @@ phpcs-security-audit-sast: pmd-apex-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/pmd-apex:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/pmd-apex:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -180,7 +179,7 @@ pmd-apex-sast: secrets-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/secrets:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/secrets:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -191,7 +190,7 @@ secrets-sast: security-code-scan-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/security-code-scan:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/security-code-scan:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -205,7 +204,7 @@ security-code-scan-sast: sobelow-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/sobelow:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/sobelow:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -218,7 +217,7 @@ sobelow-sast: spotbugs-sast: extends: .sast-analyzer image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/spotbugs:$SAST_ANALYZER_IMAGE_TAG" + name: "$SECURE_ANALYZERS_PREFIX/spotbugs:$SAST_ANALYZER_IMAGE_TAG" rules: - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' when: never @@ -229,16 +228,3 @@ spotbugs-sast: - '**/*.groovy' - '**/*.java' - '**/*.scala' - -tslint-sast: - extends: .sast-analyzer - image: - name: "$SAST_ANALYZER_IMAGE_PREFIX/tslint:$SAST_ANALYZER_IMAGE_TAG" - rules: - - if: $SAST_DISABLED || $SAST_DISABLE_DIND == 'false' - when: never - - if: $CI_COMMIT_BRANCH && - $GITLAB_FEATURES =~ /\bsast\b/ && - $SAST_DEFAULT_ANALYZERS =~ /tslint/ - exists: - - '**/*.ts' diff --git a/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml index e18f89cadd7..441a57048e1 100644 --- a/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml @@ -8,17 +8,33 @@ variables: SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers" SECRETS_ANALYZER_VERSION: "3" -secret_detection: +.secret-analyzer: stage: test image: "$SECURE_ANALYZERS_PREFIX/secrets:$SECRETS_ANALYZER_VERSION" services: [] - rules: - - if: $SECRET_DETECTION_DISABLED - when: never - - if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bsecret_detection\b/ - when: on_success artifacts: reports: secret_detection: gl-secret-detection-report.json + +secret_detection_default_branch: + extends: .secret-analyzer + rules: + - if: $SECRET_DETECTION_DISABLED + when: never + - if: $CI_DEFAULT_BRANCH == $CI_COMMIT_BRANCH && + $GITLAB_FEATURES =~ /\bsecret_detection\b/ + script: + - /analyzer run + +secret_detection: + extends: .secret-analyzer + rules: + - if: $SECRET_DETECTION_DISABLED + when: never + - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && + $GITLAB_FEATURES =~ /\bsecret_detection\b/ script: + - git fetch origin $CI_DEFAULT_BRANCH $CI_BUILD_REF_NAME + - export SECRET_DETECTION_COMMIT_TO=$(git log --left-right --cherry-pick --pretty=format:"%H" refs/remotes/origin/$CI_DEFAULT_BRANCH...refs/remotes/origin/$CI_BUILD_REF_NAME | tail -n 1) + - export SECRET_DETECTION_COMMIT_FROM=$CI_COMMIT_SHA - /analyzer run diff --git a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml index b6c05c61db1..2d2e0859373 100644 --- a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml @@ -13,7 +13,7 @@ variables: SECURE_BINARIES_ANALYZERS: >- - bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, tslint, secrets, sobelow, pmd-apex, kubesec, + bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, secrets, sobelow, pmd-apex, kubesec, bundler-audit, retire.js, gemnasium, gemnasium-maven, gemnasium-python, klar, clair-vulnerabilities-db, license-finder, @@ -40,7 +40,7 @@ variables: - docker info - env - if [ -z "$SECURE_BINARIES_IMAGE" ]; then export SECURE_BINARIES_IMAGE=${SECURE_BINARIES_IMAGE:-"registry.gitlab.com/gitlab-org/security-products/analyzers/${CI_JOB_NAME}:${SECURE_BINARIES_ANALYZER_VERSION}"}; fi - - docker pull ${SECURE_BINARIES_IMAGE} + - docker pull --quiet ${SECURE_BINARIES_IMAGE} - mkdir -p output/$(dirname ${CI_JOB_NAME}) - | if [ "$SECURE_BINARIES_SAVE_ARTIFACTS" = "true" ]; then @@ -125,13 +125,6 @@ eslint: - $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" && $SECURE_BINARIES_ANALYZERS =~ /\beslint\b/ -tslint: - extends: .download_images - only: - variables: - - $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" && - $SECURE_BINARIES_ANALYZERS =~ /\btslint\b/ - secrets: extends: .download_images only: diff --git a/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml b/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml index e6097ae322e..9dbd9b679a8 100644 --- a/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml @@ -10,8 +10,9 @@ performance: stage: performance image: docker:git variables: - URL: https://example.com - SITESPEED_VERSION: 11.2.0 + URL: '' + SITESPEED_IMAGE: sitespeedio/sitespeed.io + SITESPEED_VERSION: 13.3.0 SITESPEED_OPTIONS: '' services: - docker:stable-dind @@ -19,11 +20,10 @@ performance: - mkdir gitlab-exporter - wget -O ./gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/master/index.js - mkdir sitespeed-results - - docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --outputFolder sitespeed-results $URL $SITESPEED_OPTIONS - - mv sitespeed-results/data/performance.json performance.json + - docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io $SITESPEED_IMAGE:$SITESPEED_VERSION --plugins.add ./gitlab-exporter --outputFolder sitespeed-results $URL $SITESPEED_OPTIONS + - mv sitespeed-results/data/performance.json browser-performance.json artifacts: paths: - - performance.json - sitespeed-results/ reports: - performance: performance.json + browser_performance: browser-performance.json diff --git a/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml new file mode 100644 index 00000000000..d39bd234020 --- /dev/null +++ b/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml @@ -0,0 +1,23 @@ +# Read more about the feature here: https://docs.gitlab.com/ee/user/project/merge_requests/load_performance_testing.html + +stages: + - build + - test + - deploy + - performance + +load_performance: + stage: performance + image: docker:git + variables: + K6_IMAGE: loadimpact/k6 + K6_VERSION: 0.26.2 + K6_TEST_FILE: github.com/loadimpact/k6/samples/http_get.js + K6_OPTIONS: '' + services: + - docker:stable-dind + script: + - docker run --rm -v "$(pwd)":/k6 -w /k6 $K6_IMAGE:$K6_VERSION run $K6_TEST_FILE --summary-export=load-performance.json $K6_OPTIONS + artifacts: + reports: + load_performance: load-performance.json diff --git a/lib/gitlab/ci/templates/index.md b/lib/gitlab/ci/templates/index.md new file mode 100644 index 00000000000..ff151dd4d1a --- /dev/null +++ b/lib/gitlab/ci/templates/index.md @@ -0,0 +1,3 @@ +# Development guide for GitLab CI templates + +Please follow [the development guideline](../../../../doc/development/cicd/templates.md) diff --git a/lib/gitlab/ci/templates/npm.gitlab-ci.yml b/lib/gitlab/ci/templates/npm.gitlab-ci.yml new file mode 100644 index 00000000000..035ba52da84 --- /dev/null +++ b/lib/gitlab/ci/templates/npm.gitlab-ci.yml @@ -0,0 +1,59 @@ +default: + image: node:latest + + # Validate that the repository contains a package.json and extract a few values from it. + before_script: + - | + if [[ ! -f package.json ]]; then + echo "No package.json found! A package.json file is required to publish a package to GitLab's NPM registry." + echo 'For more information, see https://docs.gitlab.com/ee/user/packages/npm_registry/#creating-a-project' + exit 1 + fi + - NPM_PACKAGE_NAME=$(node -p "require('./package.json').name") + - NPM_PACKAGE_VERSION=$(node -p "require('./package.json').version") + +# Validate that the package name is properly scoped to the project's root namespace. +# For more information, see https://docs.gitlab.com/ee/user/packages/npm_registry/#package-naming-convention +validate_package_scope: + stage: build + script: + - | + if [[ ! $NPM_PACKAGE_NAME =~ ^@$CI_PROJECT_ROOT_NAMESPACE/ ]]; then + echo "Invalid package scope! Packages must be scoped in the root namespace of the project, e.g. \"@${CI_PROJECT_ROOT_NAMESPACE}/${CI_PROJECT_NAME}\"" + echo 'For more information, see https://docs.gitlab.com/ee/user/packages/npm_registry/#package-naming-convention' + exit 1 + fi + +# If no .npmrc if included in the repo, generate a temporary one to use during the publish step +# that is configured to publish to GitLab's NPM registry +create_npmrc: + stage: build + script: + - | + if [[ ! -f .npmrc ]]; then + echo 'No .npmrc found! Creating one now. Please review the following link for more information: https://docs.gitlab.com/ee/user/packages/npm_registry/index.html#authenticating-with-a-ci-job-token' + + { + echo '@${CI_PROJECT_ROOT_NAMESPACE}:registry=${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/' + echo '//${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/packages/npm/:_authToken=${CI_JOB_TOKEN}' + echo '//${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}' + } >> .npmrc + + fi + artifacts: + paths: + - .npmrc + +# Publish the package. If the version in package.json has not yet been published, it will be +# published to GitLab's NPM registry. If the version already exists, the publish command +# will fail and the existing package will not be updated. +publish_package: + stage: deploy + script: + - | + { + npm publish && + echo "Successfully published version ${NPM_PACKAGE_VERSION} of ${NPM_PACKAGE_NAME} to GitLab's NPM registry: ${CI_PROJECT_URL}/-/packages" + } || { + echo "No new version of ${NPM_PACKAGE_NAME} published. This is most likely because version ${NPM_PACKAGE_VERSION} already exists in GitLab's NPM registry." + } diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb index 6a9b7b2fc85..8cf355bbfc1 100644 --- a/lib/gitlab/ci/yaml_processor.rb +++ b/lib/gitlab/ci/yaml_processor.rb @@ -3,15 +3,33 @@ module Gitlab module Ci class YamlProcessor - ValidationError = Class.new(StandardError) + # ValidationError is treated like a result object in the form of an exception. + # We can return any warnings, raised during the config validation, along with + # the error object until we support multiple messages to be returned. + class ValidationError < StandardError + attr_reader :warnings + + def initialize(message, warnings: []) + @warnings = warnings + super(message) + end + end include Gitlab::Config::Entry::LegacyValidationHelpers attr_reader :stages, :jobs - ResultWithErrors = Struct.new(:content, :errors) do + class Result + attr_reader :config, :errors, :warnings + + def initialize(config: nil, errors: [], warnings: []) + @config = config + @errors = errors + @warnings = warnings + end + def valid? - errors.empty? + config.present? && errors.empty? end end @@ -20,24 +38,32 @@ module Gitlab @config = @ci_config.to_hash unless @ci_config.valid? - raise ValidationError, @ci_config.errors.first + error!(@ci_config.errors.first) end initial_parsing rescue Gitlab::Ci::Config::ConfigError => e - raise ValidationError, e.message + error!(e.message) end def self.new_with_validation_errors(content, opts = {}) - return ResultWithErrors.new('', ['Please provide content of .gitlab-ci.yml']) if content.blank? + return Result.new(errors: ['Please provide content of .gitlab-ci.yml']) if content.blank? config = Gitlab::Ci::Config.new(content, **opts) - return ResultWithErrors.new("", config.errors) unless config.valid? + return Result.new(errors: config.errors, warnings: config.warnings) unless config.valid? config = Gitlab::Ci::YamlProcessor.new(content, opts) - ResultWithErrors.new(config, []) - rescue ValidationError, Gitlab::Ci::Config::ConfigError => e - ResultWithErrors.new('', [e.message]) + Result.new(config: config, warnings: config.warnings) + + rescue ValidationError => e + Result.new(errors: [e.message], warnings: e.warnings) + + rescue Gitlab::Ci::Config::ConfigError => e + Result.new(errors: [e.message]) + end + + def warnings + @ci_config&.warnings || [] end def builds @@ -66,6 +92,7 @@ module Gitlab cache: job[:cache], resource_group_key: job[:resource_group], scheduling_type: job[:scheduling_type], + secrets: job[:secrets], options: { image: job[:image], services: job[:services], @@ -157,10 +184,14 @@ module Gitlab return unless job[:stage] unless job[:stage].is_a?(String) && job[:stage].in?(@stages) - raise ValidationError, "#{name} job: chosen stage does not exist; available stages are #{@stages.join(", ")}" + error!("#{name} job: chosen stage does not exist; available stages are #{@stages.join(", ")}") end end + def error!(message) + raise ValidationError.new(message, warnings: warnings) + end + def validate_job_dependencies!(name, job) return unless job[:dependencies] @@ -190,7 +221,7 @@ module Gitlab def validate_job_dependency!(name, dependency, dependency_type = 'dependency') unless @jobs[dependency.to_sym] - raise ValidationError, "#{name} job: undefined #{dependency_type}: #{dependency}" + error!("#{name} job: undefined #{dependency_type}: #{dependency}") end job_stage_index = stage_index(name) @@ -199,7 +230,7 @@ module Gitlab # A dependency might be defined later in the configuration # with a stage that does not exist unless dependency_stage_index.present? && dependency_stage_index < job_stage_index - raise ValidationError, "#{name} job: #{dependency_type} #{dependency} is not defined in prior stages" + error!("#{name} job: #{dependency_type} #{dependency} is not defined in prior stages") end end @@ -221,19 +252,19 @@ module Gitlab on_stop_job = @jobs[on_stop.to_sym] unless on_stop_job - raise ValidationError, "#{name} job: on_stop job #{on_stop} is not defined" + error!("#{name} job: on_stop job #{on_stop} is not defined") end unless on_stop_job[:environment] - raise ValidationError, "#{name} job: on_stop job #{on_stop} does not have environment defined" + error!("#{name} job: on_stop job #{on_stop} does not have environment defined") end unless on_stop_job[:environment][:name] == environment[:name] - raise ValidationError, "#{name} job: on_stop job #{on_stop} have different environment name" + error!("#{name} job: on_stop job #{on_stop} have different environment name") end unless on_stop_job[:environment][:action] == 'stop' - raise ValidationError, "#{name} job: on_stop job #{on_stop} needs to have action stop defined" + error!("#{name} job: on_stop job #{on_stop} needs to have action stop defined") end end end |