Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/ci')
-rw-r--r--lib/gitlab/ci/ansi2html.rb12
-rw-r--r--lib/gitlab/ci/build/artifacts/metadata.rb8
-rw-r--r--lib/gitlab/ci/build/duration_parser.rb2
-rw-r--r--lib/gitlab/ci/components/instance_path.rb48
-rw-r--r--lib/gitlab/ci/config.rb1
-rw-r--r--lib/gitlab/ci/config/entry/bridge.rb2
-rw-r--r--lib/gitlab/ci/config/entry/default.rb7
-rw-r--r--lib/gitlab/ci/config/entry/include/rules.rb5
-rw-r--r--lib/gitlab/ci/config/entry/include/rules/rule.rb10
-rw-r--r--lib/gitlab/ci/config/entry/job.rb18
-rw-r--r--lib/gitlab/ci/config/entry/processable.rb8
-rw-r--r--lib/gitlab/ci/config/external/context.rb10
-rw-r--r--lib/gitlab/ci/config/external/file/component.rb2
-rw-r--r--lib/gitlab/ci/config/external/mapper/verifier.rb2
-rw-r--r--lib/gitlab/ci/config/external/rules.rb44
-rw-r--r--lib/gitlab/ci/config/interpolation/interpolator.rb7
-rw-r--r--lib/gitlab/ci/jwt_v2.rb4
-rw-r--r--lib/gitlab/ci/parsers/sbom/cyclonedx.rb9
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb4
-rw-r--r--lib/gitlab/ci/pipeline/chain/sequence.rb1
-rw-r--r--lib/gitlab/ci/queue/metrics.rb27
-rw-r--r--lib/gitlab/ci/reports/codequality_reports.rb2
-rw-r--r--lib/gitlab/ci/reports/sbom/component.rb14
-rw-r--r--lib/gitlab/ci/reports/sbom/metadata.rb19
-rw-r--r--lib/gitlab/ci/reports/sbom/report.rb16
-rw-r--r--lib/gitlab/ci/reports/test_reports_comparer.rb2
-rw-r--r--lib/gitlab/ci/reports/test_suite.rb2
-rw-r--r--lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml4
-rw-r--r--lib/gitlab/ci/templates/Cosign.gitlab-ci.yml22
-rw-r--r--lib/gitlab/ci/templates/Docker.gitlab-ci.yml17
-rw-r--r--lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml39
-rw-r--r--lib/gitlab/ci/trace.rb6
-rw-r--r--lib/gitlab/ci/trace/stream.rb41
-rw-r--r--lib/gitlab/ci/variables/builder.rb12
-rw-r--r--lib/gitlab/ci/yaml_processor.rb6
42 files changed, 293 insertions, 152 deletions
diff --git a/lib/gitlab/ci/ansi2html.rb b/lib/gitlab/ci/ansi2html.rb
index 42a8b561d34..d581fbfda42 100644
--- a/lib/gitlab/ci/ansi2html.rb
+++ b/lib/gitlab/ci/ansi2html.rb
@@ -299,7 +299,7 @@ module Gitlab
end
def handle_new_line
- write_in_tag %{<br/>}
+ write_in_tag %(<br/>)
close_open_tags if @sections.any? && @lineno_in_section == 0
@lineno_in_section += 1
@@ -324,7 +324,7 @@ module Gitlab
return if @sections.include?(section)
@sections << section
- write_raw %{<div class="section-start" data-timestamp="#{timestamp}" data-section="#{data_section_names}" role="button"></div>}
+ write_raw %(<div class="section-start" data-timestamp="#{timestamp}" data-section="#{data_section_names}" role="button"></div>)
@lineno_in_section = 0
end
@@ -333,7 +333,7 @@ module Gitlab
# close all sections up to section
until @sections.empty?
- write_raw %{<div class="section-end" data-section="#{data_section_names}"></div>}
+ write_raw %(<div class="section-end" data-section="#{data_section_names}"></div>)
last_section = @sections.pop
break if section == last_section
@@ -423,9 +423,9 @@ module Gitlab
close_open_tags
@out << if css_classes.any?
- %{<span class="#{css_classes.join(' ')}">}
+ %(<span class="#{css_classes.join(' ')}">)
else
- %{<span>}
+ %(<span>)
end
@n_open_tags += 1
@@ -433,7 +433,7 @@ module Gitlab
def close_open_tags
while @n_open_tags > 0
- @out << %{</span>}
+ @out << %(</span>)
@n_open_tags -= 1
end
end
diff --git a/lib/gitlab/ci/build/artifacts/metadata.rb b/lib/gitlab/ci/build/artifacts/metadata.rb
index d0ab4916c90..5748b8e34cf 100644
--- a/lib/gitlab/ci/build/artifacts/metadata.rb
+++ b/lib/gitlab/ci/build/artifacts/metadata.rb
@@ -18,7 +18,11 @@ module Gitlab
def initialize(stream, path, **opts)
@stream = stream
- @path = path
+
+ # Ensure to remove any ./ prefix from the path
+ # so that the pattern matching will work as expected
+ @path = path.gsub(%r{^\./}, '')
+
@opts = opts
@full_version = read_version
end
@@ -59,7 +63,7 @@ module Gitlab
entries = {}
child_pattern = '[^/]*/?$' unless @opts[:recursive]
- match_pattern = /^#{Regexp.escape(@path)}#{child_pattern}/
+ match_pattern = /^#{Regexp.escape(path)}#{child_pattern}/
until gz.eof?
begin
diff --git a/lib/gitlab/ci/build/duration_parser.rb b/lib/gitlab/ci/build/duration_parser.rb
index 9385dccd5f3..97049a4f876 100644
--- a/lib/gitlab/ci/build/duration_parser.rb
+++ b/lib/gitlab/ci/build/duration_parser.rb
@@ -41,7 +41,7 @@ module Gitlab
def parse
return if never?
- ChronicDuration.parse(value)
+ ChronicDuration.parse(value, use_complete_matcher: true)
end
def validation_cache
diff --git a/lib/gitlab/ci/components/instance_path.rb b/lib/gitlab/ci/components/instance_path.rb
index e0ef598da1b..17c784c4d54 100644
--- a/lib/gitlab/ci/components/instance_path.rb
+++ b/lib/gitlab/ci/components/instance_path.rb
@@ -7,17 +7,19 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
LATEST_VERSION_KEYWORD = '~latest'
+ TEMPLATES_DIR = 'templates'
def self.match?(address)
address.include?('@') && address.start_with?(Settings.gitlab_ci['component_fqdn'])
end
- attr_reader :host
+ attr_reader :host, :project_file_path
def initialize(address:, content_filename:)
@full_path, @version = address.to_s.split('@', 2)
@content_filename = content_filename
@host = Settings.gitlab_ci['component_fqdn']
+ @project_file_path = nil
end
def fetch_content!(current_user:)
@@ -26,7 +28,7 @@ module Gitlab
raise Gitlab::Access::AccessDeniedError unless Ability.allowed?(current_user, :download_code, project)
- project.repository.blob_data_at(sha, project_file_path)
+ content(simple_template_path) || content(complex_template_path) || content(legacy_template_path)
end
def project
@@ -34,13 +36,6 @@ module Gitlab
end
strong_memoize_attr :project
- def project_file_path
- return unless project
-
- component_dir = instance_path.delete_prefix(project.full_path)
- File.join(component_dir, @content_filename).delete_prefix('/')
- end
-
def sha
return unless project
return latest_version_sha if version == LATEST_VERSION_KEYWORD
@@ -57,6 +52,11 @@ module Gitlab
@full_path.delete_prefix(host)
end
+ def component_path
+ instance_path.delete_prefix(project.full_path).delete_prefix('/')
+ end
+ strong_memoize_attr :component_path
+
# Given a path like "my-org/sub-group/the-project/path/to/component"
# find the project "my-org/sub-group/the-project" by looking at all possible paths.
def find_project_by_component_path(path)
@@ -75,6 +75,36 @@ module Gitlab
def latest_version_sha
project.releases.latest&.sha
end
+
+ # A simple template consists of a single file
+ def simple_template_path
+ # Extract this line and move to fetch_content once we remove legacy fetching
+ return unless templates_dir_exists? && component_path.index('/').nil?
+
+ @project_file_path = File.join(TEMPLATES_DIR, "#{component_path}.yml")
+ end
+
+ # A complex template is directory-based and may consist of multiple files.
+ # Given a path like "my-org/sub-group/the-project/templates/component"
+ # returns the entry point path: "templates/component/template.yml".
+ def complex_template_path
+ # Extract this line and move to fetch_content once we remove legacy fetching
+ return unless templates_dir_exists? && component_path.index('/').nil?
+
+ @project_file_path = File.join(TEMPLATES_DIR, component_path, @content_filename)
+ end
+
+ def legacy_template_path
+ @project_file_path = File.join(component_path, @content_filename).delete_prefix('/')
+ end
+
+ def templates_dir_exists?
+ project.repository.tree.trees.map(&:name).include?(TEMPLATES_DIR)
+ end
+
+ def content(path)
+ project.repository.blob_data_at(sha, path)
+ end
end
end
end
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 0c293c3f0ef..73d329930a5 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -161,6 +161,7 @@ module Gitlab
def build_context(project:, pipeline:, sha:, user:, parent_pipeline:, pipeline_config:)
Config::External::Context.new(
project: project,
+ pipeline: pipeline,
sha: sha || find_sha(project),
user: user,
parent_pipeline: parent_pipeline,
diff --git a/lib/gitlab/ci/config/entry/bridge.rb b/lib/gitlab/ci/config/entry/bridge.rb
index ee99354cb28..1119afab24a 100644
--- a/lib/gitlab/ci/config/entry/bridge.rb
+++ b/lib/gitlab/ci/config/entry/bridge.rb
@@ -51,7 +51,7 @@ module Gitlab
entry :parallel, Entry::Product::Parallel,
description: 'Parallel configuration for this job.',
inherit: false,
- metadata: { allowed_strategies: %i(matrix) }
+ metadata: { allowed_strategies: %i[matrix] }
attributes :when, :allow_failure, :parallel
diff --git a/lib/gitlab/ci/config/entry/default.rb b/lib/gitlab/ci/config/entry/default.rb
index e996b6b1312..476b928e471 100644
--- a/lib/gitlab/ci/config/entry/default.rb
+++ b/lib/gitlab/ci/config/entry/default.rb
@@ -14,7 +14,7 @@ module Gitlab
include ::Gitlab::Config::Entry::Inheritable
ALLOWED_KEYS = %i[before_script after_script hooks cache image services
- interruptible timeout retry tags artifacts].freeze
+ interruptible timeout retry tags artifacts id_tokens].freeze
validations do
validates :config, allowed_keys: ALLOWED_KEYS
@@ -65,6 +65,11 @@ module Gitlab
description: 'Default artifacts.',
inherit: false
+ entry :id_tokens, ::Gitlab::Config::Entry::ComposableHash,
+ description: 'Configured JWTs for this job',
+ inherit: false,
+ metadata: { composable_class: ::Gitlab::Ci::Config::Entry::IdToken }
+
private
def overwrite_entry(deps, key, current_entry)
diff --git a/lib/gitlab/ci/config/entry/include/rules.rb b/lib/gitlab/ci/config/entry/include/rules.rb
index 71418e6752d..a3799b36ece 100644
--- a/lib/gitlab/ci/config/entry/include/rules.rb
+++ b/lib/gitlab/ci/config/entry/include/rules.rb
@@ -19,11 +19,6 @@ module Gitlab
validates :config, type: Array
end
- # Remove this method when FF `ci_refactor_external_rules` is removed
- def value
- Feature.enabled?(:ci_refactor_external_rules) ? super : @config
- end
-
def composable_class
Entry::Include::Rules::Rule
end
diff --git a/lib/gitlab/ci/config/entry/include/rules/rule.rb b/lib/gitlab/ci/config/entry/include/rules/rule.rb
index 1a68e95913c..df8509eecc0 100644
--- a/lib/gitlab/ci/config/entry/include/rules/rule.rb
+++ b/lib/gitlab/ci/config/entry/include/rules/rule.rb
@@ -7,13 +7,17 @@ module Gitlab
class Include
class Rules::Rule < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
+ include ::Gitlab::Config::Entry::Configurable
include ::Gitlab::Config::Entry::Attributable
- ALLOWED_KEYS = %i[if exists when].freeze
+ ALLOWED_KEYS = %i[if exists when changes].freeze
ALLOWED_WHEN = %w[never always].freeze
attributes :if, :exists, :when
+ entry :changes, Entry::Rules::Rule::Changes,
+ description: 'File change condition rule.'
+
validations do
validates :config, presence: true
validates :config, type: { with: Hash }
@@ -27,7 +31,9 @@ module Gitlab
end
def value
- Feature.enabled?(:ci_refactor_external_rules) ? config.compact : super
+ config.merge(
+ changes: (changes_value if changes_defined?)
+ ).compact
end
end
end
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index d31d1b366c3..c40d665f320 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -13,7 +13,7 @@ module Gitlab
ALLOWED_WHEN = %w[on_success on_failure always manual delayed].freeze
ALLOWED_KEYS = %i[tags script image services start_in artifacts
cache dependencies before_script after_script hooks
- environment coverage retry parallel interruptible timeout
+ coverage retry parallel interruptible timeout
release id_tokens publish].freeze
validations do
@@ -102,10 +102,6 @@ module Gitlab
metadata: { allowed_needs: %i[job cross_dependency] },
inherit: false
- entry :environment, Entry::Environment,
- description: 'Environment configuration for this job.',
- inherit: false
-
entry :coverage, Entry::Coverage,
description: 'Coverage configuration for this job.',
inherit: false
@@ -124,7 +120,7 @@ module Gitlab
entry :id_tokens, ::Gitlab::Config::Entry::ComposableHash,
description: 'Configured JWTs for this job',
- inherit: false,
+ inherit: true,
metadata: { composable_class: ::Gitlab::Ci::Config::Entry::IdToken }
entry :publish, Entry::Publish,
@@ -160,13 +156,11 @@ module Gitlab
when: self.when,
start_in: self.start_in,
dependencies: dependencies,
- environment: environment_defined? ? environment_value : nil,
- environment_name: environment_defined? ? environment_value[:name] : nil,
coverage: coverage_defined? ? coverage_value : nil,
retry: retry_defined? ? retry_value : nil,
parallel: has_parallel? ? parallel_value : nil,
interruptible: interruptible_defined? ? interruptible_value : nil,
- timeout: has_timeout? ? ChronicDuration.parse(timeout.to_s) : nil,
+ timeout: parsed_timeout,
artifacts: artifacts_value,
release: release_value,
after_script: after_script_value,
@@ -180,6 +174,12 @@ module Gitlab
).compact
end
+ def parsed_timeout
+ return unless has_timeout?
+
+ ChronicDuration.parse(timeout.to_s, use_complete_matcher: true)
+ end
+
def ignored?
allow_failure_defined? ? static_allow_failure : manual_action?
end
diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb
index e0f0903174c..88734ac1186 100644
--- a/lib/gitlab/ci/config/entry/processable.rb
+++ b/lib/gitlab/ci/config/entry/processable.rb
@@ -15,7 +15,7 @@ module Gitlab
include ::Gitlab::Config::Entry::Inheritable
PROCESSABLE_ALLOWED_KEYS = %i[extends stage only except rules variables
- inherit allow_failure when needs resource_group].freeze
+ inherit allow_failure when needs resource_group environment].freeze
MAX_NESTING_LEVEL = 10
included do
@@ -68,6 +68,10 @@ module Gitlab
inherit: false,
default: {}
+ entry :environment, Entry::Environment,
+ description: 'Environment configuration for this job.',
+ inherit: false
+
attributes :extends, :rules, :resource_group
end
@@ -125,6 +129,8 @@ module Gitlab
root_variables_inheritance: root_variables_inheritance,
only: only_value,
except: except_value,
+ environment: environment_defined? ? environment_value : nil,
+ environment_name: environment_defined? ? environment_value[:name] : nil,
resource_group: resource_group }.compact
end
diff --git a/lib/gitlab/ci/config/external/context.rb b/lib/gitlab/ci/config/external/context.rb
index c57391d355c..0a524fdba66 100644
--- a/lib/gitlab/ci/config/external/context.rb
+++ b/lib/gitlab/ci/config/external/context.rb
@@ -9,22 +9,21 @@ module Gitlab
TimeoutError = Class.new(StandardError)
- TEMP_MAX_INCLUDES = 100 # For logging; to be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/396776
-
include ::Gitlab::Utils::StrongMemoize
attr_reader :project, :sha, :user, :parent_pipeline, :variables, :pipeline_config
- attr_reader :expandset, :execution_deadline, :logger, :max_includes, :max_total_yaml_size_bytes
+ attr_reader :pipeline, :expandset, :execution_deadline, :logger, :max_includes, :max_total_yaml_size_bytes
attr_accessor :total_file_size_in_bytes
delegate :instrument, to: :logger
def initialize(
- project: nil, sha: nil, user: nil, parent_pipeline: nil, variables: nil,
+ project: nil, pipeline: nil, sha: nil, user: nil, parent_pipeline: nil, variables: nil,
pipeline_config: nil, logger: nil
)
@project = project
+ @pipeline = pipeline
@sha = sha
@user = user
@parent_pipeline = parent_pipeline
@@ -60,6 +59,7 @@ module Gitlab
def mutate(attrs = {})
self.class.new(**attrs) do |ctx|
+ ctx.pipeline = pipeline
ctx.expandset = expandset
ctx.execution_deadline = execution_deadline
ctx.logger = logger
@@ -106,7 +106,7 @@ module Gitlab
protected
- attr_writer :expandset, :execution_deadline, :logger, :max_includes, :max_total_yaml_size_bytes
+ attr_writer :pipeline, :expandset, :execution_deadline, :logger, :max_includes, :max_total_yaml_size_bytes
private
diff --git a/lib/gitlab/ci/config/external/file/component.rb b/lib/gitlab/ci/config/external/file/component.rb
index 15cc0783b86..de6de1bb7a8 100644
--- a/lib/gitlab/ci/config/external/file/component.rb
+++ b/lib/gitlab/ci/config/external/file/component.rb
@@ -18,6 +18,8 @@ module Gitlab
def content
return unless component_result.success?
+ ::Gitlab::UsageDataCounters::HLLRedisCounter.track_event('cicd_component_usage', values: context.user.id)
+
component_result.payload.fetch(:content)
end
strong_memoize_attr :content
diff --git a/lib/gitlab/ci/config/external/mapper/verifier.rb b/lib/gitlab/ci/config/external/mapper/verifier.rb
index 580cae8a207..0e296aa0b5b 100644
--- a/lib/gitlab/ci/config/external/mapper/verifier.rb
+++ b/lib/gitlab/ci/config/external/mapper/verifier.rb
@@ -40,7 +40,7 @@ module Gitlab
file.validate_content! if file.valid?
file.load_and_validate_expanded_hash! if file.valid?
- next unless Feature.enabled?(:introduce_ci_max_total_yaml_size_bytes, context.project) && file.valid?
+ next unless file.valid?
# We are checking the file.content.to_s because that is returning the actual content of the file,
# whereas file.content would return the BatchLoader.
diff --git a/lib/gitlab/ci/config/external/rules.rb b/lib/gitlab/ci/config/external/rules.rb
index 0e6209460e0..05266fbff0c 100644
--- a/lib/gitlab/ci/config/external/rules.rb
+++ b/lib/gitlab/ci/config/external/rules.rb
@@ -5,29 +5,19 @@ module Gitlab
class Config
module External
class Rules
- # Remove these two constants when FF `ci_refactor_external_rules` is removed
- ALLOWED_KEYS = Entry::Include::Rules::Rule::ALLOWED_KEYS
- ALLOWED_WHEN = Entry::Include::Rules::Rule::ALLOWED_WHEN
-
InvalidIncludeRulesError = Class.new(Mapper::Error)
def initialize(rule_hashes)
- if Feature.enabled?(:ci_refactor_external_rules)
- return unless rule_hashes
-
- # We must compose the include rules entry here because included
- # files are expanded before `@root.compose!` runs in Ci::Config.
- rules_entry = Entry::Include::Rules.new(rule_hashes)
- rules_entry.compose!
+ return unless rule_hashes
- raise InvalidIncludeRulesError, "include:#{rules_entry.errors.first}" unless rules_entry.valid?
+ # We must compose the include rules entry here because included
+ # files are expanded before `@root.compose!` runs in Ci::Config.
+ rules_entry = Entry::Include::Rules.new(rule_hashes)
+ rules_entry.compose!
- @rule_list = Build::Rules::Rule.fabricate_list(rules_entry.value)
- else
- validate(rule_hashes)
+ raise InvalidIncludeRulesError, "include:#{rules_entry.errors.first}" unless rules_entry.valid?
- @rule_list = Build::Rules::Rule.fabricate_list(rule_hashes)
- end
+ @rule_list = Build::Rules::Rule.fabricate_list(rules_entry.value)
end
def evaluate(context)
@@ -38,28 +28,14 @@ module Gitlab
else
Result.new('never')
end
+ rescue Build::Rules::Rule::Clause::ParseError => e
+ raise InvalidIncludeRulesError, "include:#{e.message}"
end
private
def match_rule(context)
- @rule_list.find { |rule| rule.matches?(nil, context) }
- end
-
- # Remove this method when FF `ci_refactor_external_rules` is removed
- def validate(rule_hashes)
- return unless rule_hashes.is_a?(Array)
-
- rule_hashes.each do |rule_hash|
- next if (rule_hash.keys - ALLOWED_KEYS).empty? && valid_when?(rule_hash)
-
- raise InvalidIncludeRulesError, "invalid include rule: #{rule_hash}"
- end
- end
-
- # Remove this method when FF `ci_refactor_external_rules` is removed
- def valid_when?(rule_hash)
- rule_hash[:when].nil? || rule_hash[:when].in?(ALLOWED_WHEN)
+ @rule_list.find { |rule| rule.matches?(context.pipeline, context) }
end
Result = Struct.new(:when) do
diff --git a/lib/gitlab/ci/config/interpolation/interpolator.rb b/lib/gitlab/ci/config/interpolation/interpolator.rb
index 58965890184..95c419d7427 100644
--- a/lib/gitlab/ci/config/interpolation/interpolator.rb
+++ b/lib/gitlab/ci/config/interpolation/interpolator.rb
@@ -37,7 +37,12 @@ module Gitlab
def interpolate!
return @errors.push(config.error) unless config.valid?
- return @errors.push('unknown input arguments') if inputs_without_header?
+
+ if inputs_without_header?
+ return @errors.push(
+ _('Given inputs not defined in the `spec` section of the included configuration file'))
+ end
+
return @result ||= config.content unless config.has_header?
return @errors.concat(header.errors) unless header.valid?
diff --git a/lib/gitlab/ci/jwt_v2.rb b/lib/gitlab/ci/jwt_v2.rb
index 8c730a9548f..29beba4774a 100644
--- a/lib/gitlab/ci/jwt_v2.rb
+++ b/lib/gitlab/ci/jwt_v2.rb
@@ -61,10 +61,6 @@ module Gitlab
pipeline_source: pipeline.source&.to_sym,
pipeline_source_bridge: pipeline.source_bridge
)
- rescue StandardError => e
- # We don't want endpoints relying on this code to fail if there's an error here.
- Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e, pipeline_id: pipeline.id)
- nil
end
strong_memoize_attr(:project_config)
diff --git a/lib/gitlab/ci/parsers/sbom/cyclonedx.rb b/lib/gitlab/ci/parsers/sbom/cyclonedx.rb
index bc62fbe55ec..1e5200e8682 100644
--- a/lib/gitlab/ci/parsers/sbom/cyclonedx.rb
+++ b/lib/gitlab/ci/parsers/sbom/cyclonedx.rb
@@ -58,6 +58,15 @@ module Gitlab
properties = data.dig('metadata', 'properties')
source = CyclonedxProperties.parse_source(properties)
report.set_source(source) if source
+
+ tools = data.dig('metadata', 'tools')
+ authors = data.dig('metadata', 'authors')
+
+ report.metadata = ::Gitlab::Ci::Reports::Sbom::Metadata.new.tap do |metadata|
+ metadata.tools = tools if tools
+ metadata.authors = authors if authors
+ metadata.properties = properties if properties
+ end
end
def parse_components
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index 4bc2f6c7be7..cc3aa33e93b 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -128,10 +128,6 @@ module Gitlab
.observe({ plan: project.actual_plan_name }, jobs_count)
end
- def observe_pipeline_includes_count(pipeline)
- logger.observe(:pipeline_includes_count, pipeline.config_metadata&.[](:includes)&.count, once: true)
- end
-
def increment_pipeline_failure_reason_counter(reason)
metrics.pipeline_failure_reason_counter
.increment(reason: (reason || :unknown_failure).to_s)
diff --git a/lib/gitlab/ci/pipeline/chain/sequence.rb b/lib/gitlab/ci/pipeline/chain/sequence.rb
index dd097187955..de147914850 100644
--- a/lib/gitlab/ci/pipeline/chain/sequence.rb
+++ b/lib/gitlab/ci/pipeline/chain/sequence.rb
@@ -30,7 +30,6 @@ module Gitlab
@command.observe_creation_duration(current_monotonic_time - @start)
@command.observe_pipeline_size(@pipeline)
@command.observe_jobs_count_in_alive_pipelines
- @command.observe_pipeline_includes_count(@pipeline)
@pipeline
end
diff --git a/lib/gitlab/ci/queue/metrics.rb b/lib/gitlab/ci/queue/metrics.rb
index a18542288c9..db1b53e52e0 100644
--- a/lib/gitlab/ci/queue/metrics.rb
+++ b/lib/gitlab/ci/queue/metrics.rb
@@ -14,7 +14,6 @@ module Gitlab
METRICS_SHARD_TAG_PREFIX = 'metrics_shard::'
DEFAULT_METRICS_SHARD = 'default'
- JOBS_RUNNING_FOR_PROJECT_MAX_BUCKET = 5
OPERATION_COUNTERS = [
:build_can_pick,
@@ -57,7 +56,7 @@ module Gitlab
def register_success(job)
labels = { shared_runner: runner.instance_type?,
- jobs_running_for_project: jobs_running_for_project(job),
+ jobs_running_for_project: job.project_jobs_running_on_instance_runners_count,
shard: DEFAULT_METRICS_SHARD }
if runner.instance_type?
@@ -65,7 +64,7 @@ module Gitlab
labels[:shard] = shard.gsub(METRICS_SHARD_TAG_PREFIX, '') if shard
end
- self.class.job_queue_duration_seconds.observe(labels, Time.current - job.queued_at) unless job.queued_at.nil?
+ self.class.job_queue_duration_seconds.observe(labels, job.time_in_queue_seconds) unless job.queued_at.nil?
self.class.attempt_counter.increment
end
@@ -231,28 +230,6 @@ module Gitlab
Gitlab::Metrics.histogram(name, comment, labels, buckets)
end
end
-
- private
-
- # rubocop: disable CodeReuse/ActiveRecord
- def jobs_running_for_project(job)
- return '+Inf' unless runner.instance_type?
-
- # excluding currently started job
- running_jobs_count = running_jobs_relation(job)
- .limit(JOBS_RUNNING_FOR_PROJECT_MAX_BUCKET + 1).count - 1
-
- if running_jobs_count < JOBS_RUNNING_FOR_PROJECT_MAX_BUCKET
- running_jobs_count
- else
- "#{JOBS_RUNNING_FOR_PROJECT_MAX_BUCKET}+"
- end
- end
-
- def running_jobs_relation(job)
- ::Ci::RunningBuild.instance_type.where(project_id: job.project_id)
- end
- # rubocop: enable CodeReuse/ActiveRecord
end
end
end
diff --git a/lib/gitlab/ci/reports/codequality_reports.rb b/lib/gitlab/ci/reports/codequality_reports.rb
index aba2d2e8b19..edcb17a61a7 100644
--- a/lib/gitlab/ci/reports/codequality_reports.rb
+++ b/lib/gitlab/ci/reports/codequality_reports.rb
@@ -6,7 +6,7 @@ module Gitlab
class CodequalityReports
attr_reader :degradations, :error_message
- SEVERITY_PRIORITIES = %w(blocker critical major minor info unknown).map.with_index.to_h.freeze # { "blocker" => 0, "critical" => 1 ... }
+ SEVERITY_PRIORITIES = %w[blocker critical major minor info unknown].map.with_index.to_h.freeze # { "blocker" => 0, "critical" => 1 ... }
CODECLIMATE_SCHEMA_PATH = Rails.root.join('app', 'validators', 'json_schemas', 'codeclimate.json').to_s
def initialize
diff --git a/lib/gitlab/ci/reports/sbom/component.rb b/lib/gitlab/ci/reports/sbom/component.rb
index 51fd6af7bc4..59816e75b2c 100644
--- a/lib/gitlab/ci/reports/sbom/component.rb
+++ b/lib/gitlab/ci/reports/sbom/component.rb
@@ -7,7 +7,7 @@ module Gitlab
class Component
include Gitlab::Utils::StrongMemoize
- attr_reader :component_type, :version
+ attr_reader :component_type, :version, :path
def initialize(type:, name:, purl:, version:)
@component_type = type
@@ -31,12 +31,24 @@ module Gitlab
end
strong_memoize_attr :purl
+ def purl_type
+ purl.type
+ end
+
+ def type
+ component_type
+ end
+
def name
return @name unless purl
[purl.namespace, purl.name].compact.join('/')
end
+ def key
+ [name, version, purl&.type]
+ end
+
private
def supported_component_type?
diff --git a/lib/gitlab/ci/reports/sbom/metadata.rb b/lib/gitlab/ci/reports/sbom/metadata.rb
new file mode 100644
index 00000000000..8945259d331
--- /dev/null
+++ b/lib/gitlab/ci/reports/sbom/metadata.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Reports
+ module Sbom
+ class Metadata
+ attr_accessor :tools, :authors, :properties, :timestamp
+
+ def initialize(tools: [], authors: [], properties: [])
+ @tools = tools
+ @authors = authors
+ @properties = properties
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/reports/sbom/report.rb b/lib/gitlab/ci/reports/sbom/report.rb
index 51fa8ce0d2e..9a71c67388d 100644
--- a/lib/gitlab/ci/reports/sbom/report.rb
+++ b/lib/gitlab/ci/reports/sbom/report.rb
@@ -5,10 +5,24 @@ module Gitlab
module Reports
module Sbom
class Report
- attr_reader :components, :source, :errors
+ # This represents the attributes defined in cycloneDX Schema
+ # https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/validators/json_schemas/cyclonedx_report.json#L7
+ BOM_FORMAT = 'CycloneDX'
+ SPEC_VERSION = '1.4'
+ VERSION = 1
+
+ attr_reader :source, :errors
+ attr_accessor :sbom_attributes, :metadata, :components
def initialize
+ @sbom_attributes = {
+ bom_format: BOM_FORMAT,
+ spec_version: SPEC_VERSION,
+ serial_number: "urn:uuid:#{SecureRandom.uuid}",
+ version: VERSION
+ }
@components = []
+ @metadata = ::Gitlab::Ci::Reports::Sbom::Metadata.new
@errors = []
end
diff --git a/lib/gitlab/ci/reports/test_reports_comparer.rb b/lib/gitlab/ci/reports/test_reports_comparer.rb
index 497831ae5a7..0ea2d793eea 100644
--- a/lib/gitlab/ci/reports/test_reports_comparer.rb
+++ b/lib/gitlab/ci/reports/test_reports_comparer.rb
@@ -29,7 +29,7 @@ module Gitlab
end
end
- %w(total_count resolved_count failed_count error_count).each do |method|
+ %w[total_count resolved_count failed_count error_count].each do |method|
define_method(method) do
# rubocop: disable CodeReuse/ActiveRecord
suite_comparers.sum { |suite| suite.public_send(method) } # rubocop:disable GitlabSecurity/PublicSend
diff --git a/lib/gitlab/ci/reports/test_suite.rb b/lib/gitlab/ci/reports/test_suite.rb
index dcc593b4403..c681727a43d 100644
--- a/lib/gitlab/ci/reports/test_suite.rb
+++ b/lib/gitlab/ci/reports/test_suite.rb
@@ -77,7 +77,7 @@ module Gitlab
def +(other)
self.class.new.tap do |test_suite|
- test_suite.name = self.name
+ test_suite.name = other.name
test_suite.test_cases = self.test_cases.deep_merge(other.test_cases)
test_suite.total_time = self.total_time + other.total_time
end
diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index 6e2faf33a2f..fa1d8bec7e6 100644
--- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -65,6 +65,10 @@ variables:
DOCKER_TLS_CERTDIR: "" # https://gitlab.com/gitlab-org/gitlab-runner/issues/4501
+ # License-Scanning job is removed from GitLab 16.3
+ # This is the fix for https://gitlab.com/gitlab-org/gitlab/-/issues/422791
+ LICENSE_MANAGEMENT_DISABLED: "true"
+
stages:
- build
- test
diff --git a/lib/gitlab/ci/templates/Cosign.gitlab-ci.yml b/lib/gitlab/ci/templates/Cosign.gitlab-ci.yml
new file mode 100644
index 00000000000..48c9422b469
--- /dev/null
+++ b/lib/gitlab/ci/templates/Cosign.gitlab-ci.yml
@@ -0,0 +1,22 @@
+# To contribute improvements to CI/CD templates, please follow the Development guide at:
+# https://docs.gitlab.com/ee/development/cicd/templates.html
+# This specific template is located at:
+# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Cosign.gitlab-ci.yml
+
+# This template extends Docker.gitlab-ci.yml to sign the image with Cosign after building.
+# This allows you to verify that an image was built by a trusted pipeline before running it.
+# See https://docs.gitlab.com/ee/ci/yaml/signing_examples.html for more details.
+
+include:
+ template: Docker.gitlab-ci.yml
+
+docker-build:
+ variables:
+ COSIGN_YES: "true" # Used by Cosign to skip confirmation prompts for non-destructive operations
+ id_tokens:
+ SIGSTORE_ID_TOKEN: # Used by Cosign to get certificate from Fulcio
+ aud: sigstore
+ after_script:
+ - apk add --update cosign
+ - IMAGE_DIGEST="$(docker inspect --format='{{index .RepoDigests 0}}' "$DOCKER_IMAGE_NAME")"
+ - cosign sign "$IMAGE_DIGEST"
diff --git a/lib/gitlab/ci/templates/Docker.gitlab-ci.yml b/lib/gitlab/ci/templates/Docker.gitlab-ci.yml
index 8f5f0e2c451..1aa346aec67 100644
--- a/lib/gitlab/ci/templates/Docker.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Docker.gitlab-ci.yml
@@ -15,21 +15,20 @@ docker-build:
stage: build
services:
- docker:dind
+ variables:
+ DOCKER_IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
- # Default branch leaves tag empty (= latest tag)
- # All other branches are tagged with the escaped branch name (commit ref slug)
+ # All branches are tagged with $DOCKER_IMAGE_NAME (defaults to commit ref slug)
+ # Default branch is also tagged with `latest`
script:
+ - docker build --pull -t "$DOCKER_IMAGE_NAME" .
+ - docker push "$DOCKER_IMAGE_NAME"
- |
if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
- tag=""
- echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'"
- else
- tag=":$CI_COMMIT_REF_SLUG"
- echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
+ docker tag "$DOCKER_IMAGE_NAME" "$CI_REGISTRY_IMAGE:latest"
+ docker push "$CI_REGISTRY_IMAGE:latest"
fi
- - docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" .
- - docker push "$CI_REGISTRY_IMAGE${tag}"
# Run this job in a branch where a Dockerfile exists
rules:
- if: $CI_COMMIT_BRANCH
diff --git a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
index c1aedbe1111..07bc3fbe795 100644
--- a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_BUILD_IMAGE_VERSION: 'v1.38.1'
+ AUTO_BUILD_IMAGE_VERSION: 'v1.41.0'
build:
stage: build
diff --git a/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml
index c1aedbe1111..07bc3fbe795 100644
--- a/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_BUILD_IMAGE_VERSION: 'v1.38.1'
+ AUTO_BUILD_IMAGE_VERSION: 'v1.41.0'
build:
stage: build
diff --git a/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml
index 192d06bfa14..5cee19a746c 100644
--- a/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml
@@ -40,6 +40,7 @@ container_scanning:
reports:
container_scanning: gl-container-scanning-report.json
dependency_scanning: gl-dependency-scanning-report.json
+ cyclonedx: "**/gl-sbom-*.cdx.json"
paths: [gl-container-scanning-report.json, gl-dependency-scanning-report.json, "**/gl-sbom-*.cdx.json"]
dependencies: []
script:
diff --git a/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml
index 9a4c75e7402..ade4be99f18 100644
--- a/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml
@@ -40,6 +40,7 @@ container_scanning:
reports:
container_scanning: gl-container-scanning-report.json
dependency_scanning: gl-dependency-scanning-report.json
+ cyclonedx: "**/gl-sbom-*.cdx.json"
paths: [gl-container-scanning-report.json, gl-dependency-scanning-report.json, "**/gl-sbom-*.cdx.json"]
dependencies: []
script:
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 7b2fb49b65e..e9ba938142d 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 @@
variables:
- DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.53.0'
+ DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.56.0'
.dast-auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
index 1e482ccca82..eaaf171e4b5 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_DEPLOY_IMAGE_VERSION: 'v2.53.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.56.0'
.auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
index 6eac691b293..d2e448fb6a1 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_DEPLOY_IMAGE_VERSION: 'v2.53.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.56.0'
.auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml b/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
index 30767e66649..1468cf9c7c6 100644
--- a/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
@@ -3,17 +3,17 @@
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
-# Use this template to run MATLAB and Simulink as part of your CI/CD pipeline. The template includes three jobs:
+# Use this template to build and test your MATLAB project as part of your CI/CD pipeline. The template includes four jobs:
# - `command`: Run MATLAB scripts, functions, and statements.
# - `test`: Run tests authored using the MATLAB unit testing framework or Simulink Test.
# - `test_artifacts`: Run MATLAB and Simulink tests, and generate test and coverage artifacts.
+# - `build`: Run a build using the MATLAB build tool.
#
# The jobs in the template use the `matlab -batch` syntax to start MATLAB. The `-batch` option is supported
# in MATLAB R2019a and later.
#
# You can copy and paste one or more jobs in this template into your `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
-#
# Your runner must use the Docker executor to run MATLAB within a container. The [MATLAB Container on Docker Hub][1]
# lets you run your build using MATLAB R2020b or a later release. If your build requires additional toolboxes, use a
@@ -24,7 +24,7 @@
# [2] https://www.mathworks.com/help/cloudcenter/ug/create-a-custom-matlab-container.html
# The jobs in this template incorporate the contents of a hidden `.matlab_defaults` job. You need to
-# configure this job before running the `command`, `test`, and `test_artifacts` jobs. To configure the job:
+# configure this job before running the `command`, `test`, `test_artifacts`, and `build` jobs. To configure the job:
# - Specify the name of the MATLAB container image you want to use.
# - Set the `MLM_LICENSE_FILE` environment variable using the port number and DNS address for your network license manager.
#
@@ -40,17 +40,17 @@
#
command:
extends: .matlab_defaults
- script: matlab -batch mycommand
+ script: matlab -batch "mycommand"
# If you specify more than one script, function, or statement, use a comma or semicolon to separate them.
# For example, to run `myscript.m` in a folder named `myfolder` located in the root of the repository,
-# you can specify `mycommand` like this:
+# you can specify `"mycommand"` like this:
#
# "addpath('myfolder'), myscript"
#
# MATLAB exits with exit code 0 if the specified script, function, or statement executes successfully without
# error. Otherwise, MATLAB terminates with a nonzero exit code, which causes the job to fail. To have the
-# job fail in certain conditions, use the [`assert`][3] or [`error`][4] functions.
+# job fail in certain conditions, use the [`assert`][3] or [`error`][4] function.
#
# [3] https://www.mathworks.com/help/matlab/ref/assert.html
# [4] https://www.mathworks.com/help/matlab/ref/error.html
@@ -62,7 +62,7 @@ test:
extends: .matlab_defaults
script: matlab -batch "results = runtests('IncludeSubfolders',true), assertSuccess(results);"
-# By default, the job includes any files in your [MATLAB Project][7] that have a `Test` label. If your repository
+# By default, the job includes any files in your [MATLAB project][7] that have a `Test` label. If your repository
# does not have a MATLAB project, then the job includes all tests in the root of your repository or in any of
# its subfolders.
#
@@ -71,9 +71,9 @@ test:
# [7] https://www.mathworks.com/help/matlab/projects.html
# The `test_artifacts` job runs your tests and additionally generates test and coverage artifacts.
-# It uses the plugin classes in the [`matlab.unittest.plugins`][8] package to generate a JUnit test results
-# report and a Cobertura code coverage report. Like the `test` job, this job runs all the tests in your
-# project and fails the build if any of the tests fail.
+# It uses the plugin classes in the [`matlab.unittest.plugins`][8] package to produce test results
+# in JUnit-style XML format and code coverage results in Cobertura XML format. Like the `test` job,
+# this job runs all the tests in your project and fails the build if any of the tests fail.
#
test_artifacts:
extends: .matlab_defaults
@@ -110,3 +110,22 @@ test_artifacts:
#
# [8] https://www.mathworks.com/help/matlab/ref/matlab.unittest.plugins-package.html
# [9] https://www.mathworks.com/help/matlab/matlab_prog/generate-artifacts-using-matlab-unit-test-plugins.html
+
+# Starting in R2022b, the `build` job runs a build using the MATLAB build tool. You can use this job to run the
+# tasks specified in a file named `buildfile.m` in the root of your repository.
+#
+build:
+ extends: .matlab_defaults
+ script: matlab -batch "buildtool"
+
+# The job executes the [`buildtool`][10] command to run a build using the default tasks in `buildfile.m`
+# as well as all the tasks on which they depend. To run specific tasks instead, specify them as a space-separated
+# list in the job. For example, to run the tasks named `task1` and `task2` and their dependencies, substitute
+# `"buildtool"` with `"buildtool task1 task2"`.
+#
+# MATLAB exits with exit code 0 if the build runs successfully. Otherwise, MATLAB terminates with a nonzero
+# exit code, which causes the job to fail. For more information about the MATLAB build tool,
+# see [Create and Run Tasks Using Build Tool][11].
+#
+# [10] https://www.mathworks.com/help/matlab/ref/buildtool.html
+# [11] https://www.mathworks.com/help/matlab/matlab_prog/create-and-run-tasks-using-build-tool.html
diff --git a/lib/gitlab/ci/trace.rb b/lib/gitlab/ci/trace.rb
index 2dc7bbc391e..f4ba9100812 100644
--- a/lib/gitlab/ci/trace.rb
+++ b/lib/gitlab/ci/trace.rb
@@ -30,9 +30,9 @@ module Gitlab
@job = job
end
- def html(last_lines: nil)
+ def html(last_lines: nil, max_size: nil)
read do |stream|
- stream.html(last_lines: last_lines)
+ stream.html(last_lines: last_lines, max_size: max_size)
end
end
@@ -290,7 +290,7 @@ module Gitlab
if consistent_archived_trace?(build)
::Ci::Build
.sticking
- .unstick_or_continue_sticking(LOAD_BALANCING_STICKING_NAMESPACE, build.id)
+ .find_caught_up_replica(LOAD_BALANCING_STICKING_NAMESPACE, build.id)
end
yield
diff --git a/lib/gitlab/ci/trace/stream.rb b/lib/gitlab/ci/trace/stream.rb
index dd435ba05b7..ef494a79d9a 100644
--- a/lib/gitlab/ci/trace/stream.rb
+++ b/lib/gitlab/ci/trace/stream.rb
@@ -53,18 +53,20 @@ module Gitlab
append(data, 0)
end
- def raw(last_lines: nil)
+ def raw(last_lines: nil, max_size: nil)
return unless valid?
- if last_lines.to_i > 0
+ if max_size.to_i > 0
+ read_last_lines_with_max_size(last_lines, max_size)
+ elsif last_lines.to_i > 0
read_last_lines(last_lines)
else
stream.read
end.force_encoding(Encoding.default_external)
end
- def html(last_lines: nil)
- text = raw(last_lines: last_lines)
+ def html(last_lines: nil, max_size: nil)
+ text = raw(last_lines: last_lines, max_size: max_size)
buffer = StringIO.new(text)
::Gitlab::Ci::Ansi2html.convert(buffer).html
end
@@ -117,6 +119,37 @@ module Gitlab
to_enum(:reverse_line).first(limit).reverse.join
end
+ def read_last_lines_with_max_size(limit, max_size)
+ linesleft = limit
+ result = ''
+
+ reverse_line_with_max_size(max_size) do |line|
+ result = line + result
+ unless linesleft.nil?
+ linesleft -= 1
+ break if linesleft <= 0
+ end
+ end
+
+ result
+ end
+
+ def reverse_line_with_max_size(max_size)
+ stream.seek(0, IO::SEEK_END)
+ debris = ''
+ sizeleft = max_size
+
+ until sizeleft <= 0 || (buf = read_backward([BUFFER_SIZE, sizeleft].min)).empty?
+ sizeleft -= buf.bytesize
+ debris, *lines = (buf + debris).each_line.to_a
+ lines.reverse_each do |line|
+ yield(line.force_encoding(Encoding.default_external))
+ end
+ end
+
+ yield(debris.force_encoding(Encoding.default_external)) unless debris.empty?
+ end
+
def reverse_line
stream.seek(0, IO::SEEK_END)
debris = ''
diff --git a/lib/gitlab/ci/variables/builder.rb b/lib/gitlab/ci/variables/builder.rb
index cae3a966bc6..c279af6acfc 100644
--- a/lib/gitlab/ci/variables/builder.rb
+++ b/lib/gitlab/ci/variables/builder.rb
@@ -17,7 +17,7 @@ module Gitlab
def scoped_variables(job, environment:, dependencies:)
Gitlab::Ci::Variables::Collection.new.tap do |variables|
- variables.concat(predefined_variables(job))
+ variables.concat(predefined_variables(job, environment))
variables.concat(project.predefined_variables)
variables.concat(pipeline_variables_builder.predefined_variables)
variables.concat(job.runner.predefined_variables) if job.runnable? && job.runner
@@ -126,7 +126,7 @@ module Gitlab
delegate :project, to: :pipeline
- def predefined_variables(job)
+ def predefined_variables(job, environment)
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'CI_JOB_NAME', value: job.name)
variables.append(key: 'CI_JOB_NAME_SLUG', value: job_name_slug(job))
@@ -137,8 +137,12 @@ module Gitlab
variables.append(key: 'CI_NODE_INDEX', value: job.options[:instance].to_s) if job.options&.include?(:instance)
variables.append(key: 'CI_NODE_TOTAL', value: ci_node_total_value(job).to_s)
- # Set environment name here so we can access it when evaluating the job's rules
- variables.append(key: 'CI_ENVIRONMENT_NAME', value: job.environment) if job.environment
+ if environment.present?
+ variables.append(key: 'CI_ENVIRONMENT_NAME', value: environment)
+ variables.append(key: 'CI_ENVIRONMENT_ACTION', value: job.environment_action)
+ variables.append(key: 'CI_ENVIRONMENT_TIER', value: job.environment_tier)
+ variables.append(key: 'CI_ENVIRONMENT_URL', value: job.environment_url) if job.environment_url
+ end
end
end
diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb
index c69d9218a66..3a0173d1548 100644
--- a/lib/gitlab/ci/yaml_processor.rb
+++ b/lib/gitlab/ci/yaml_processor.rb
@@ -129,6 +129,12 @@ module Gitlab
error!("#{name} job: undefined #{dependency_type}: #{dependency}")
end
+ # A parallel job's name is expanded in Config::Normalizer so we must revalidate the name length here
+ if dependency_type == 'need' && dependency.length > ::Ci::BuildNeed::MAX_JOB_NAME_LENGTH
+ error!("#{name} job: need `#{dependency}` name is too long " \
+ "(maximum is #{::Ci::BuildNeed::MAX_JOB_NAME_LENGTH} characters)")
+ end
+
job_stage_index = stage_index(name)
dependency_stage_index = stage_index(dependency)