From 97cf42fc5d4201bc48e49245f3b6381379d13037 Mon Sep 17 00:00:00 2001 From: lma-git Date: Fri, 29 Aug 2025 23:19:32 -0700 Subject: [PATCH 1/5] Update options/yaml_variables with feature flag Updates the setters for options and yaml_variables with the feature flag 'stop_writing_builds_metadata'. Refactors and updates the related spec tests. --- app/models/concerns/ci/metadatable.rb | 2 + spec/models/ci/build_spec.rb | 88 ------------------- .../ci/deployable_shared_examples.rb | 2 +- 3 files changed, 3 insertions(+), 89 deletions(-) diff --git a/app/models/concerns/ci/metadatable.rb b/app/models/concerns/ci/metadatable.rb index 96123c2c79ccb5..f5851b601eb6fc 100644 --- a/app/models/concerns/ci/metadatable.rb +++ b/app/models/concerns/ci/metadatable.rb @@ -200,6 +200,8 @@ def read_metadata_attribute(legacy_key, metadata_key, job_definition_key, defaul end def write_metadata_attribute(legacy_key, metadata_key, value) + return unless can_write_metadata? + ensure_metadata.write_attribute(metadata_key, value) write_attribute(legacy_key, nil) end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 43c49310b5085d..d6045f715c8761 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -5017,94 +5017,6 @@ def run_job_without_exception subject(:job) { create(:ci_build, pipeline: pipeline) } end - describe '#read_metadata_attribute' do - let(:build) { create(:ci_build, :degenerated, pipeline: pipeline) } - let(:build_options) { { key: 'build' } } - let(:job_definition_options) { { key: 'definition' } } - let(:metadata_options) { { key: 'metadata' } } - let(:default_options) { { key: 'default' } } - - subject { build.send(:read_metadata_attribute, :options, :config_options, :options, default_options) } - - before do - # Remove when FF `read_from_new_ci_destinations` is removed - build.clear_memoization(:read_from_new_destination?) - end - - context 'when all destination options are set' do - before do - build.write_attribute(:options, build_options) - build.ensure_metadata.write_attribute(:config_options, metadata_options) - build.build_job_definition.write_attribute(:config, { options: job_definition_options }) - end - - it 'prefers build options' do - is_expected.to eq(build_options) - end - end - - context 'when only job definition and metadata options are set' do - before do - build.ensure_metadata.write_attribute(:config_options, metadata_options) - build.build_job_definition.write_attribute(:config, { options: job_definition_options }) - end - - it 'returns job definition options' do - is_expected.to eq(job_definition_options) - end - - context 'when FF `read_from_new_ci_destinations` is disabled' do - before do - stub_feature_flags(read_from_new_ci_destinations: false) - end - - it 'returns metadata options' do - is_expected.to eq(metadata_options) - end - end - end - - context 'when only metadata options is set' do - before do - build.write_attribute(:options, nil) - build.ensure_metadata.write_attribute(:config_options, metadata_options) - end - - it 'returns metadata options' do - is_expected.to eq(metadata_options) - end - end - - context 'when none is set' do - it 'returns default value' do - is_expected.to eq(default_options) - end - end - end - - describe '#write_metadata_attribute' do - let(:options) { { key: "new options" } } - let(:existing_options) { { key: "existing options" } } - - subject { build.send(:write_metadata_attribute, :options, :config_options, options) } - - context 'when data in build is already set' do - let(:build) { create(:ci_build, pipeline: pipeline, options: existing_options) } - - it 'does set metadata options' do - subject - - expect(build.metadata.read_attribute(:config_options)).to eq(options) - end - - it 'does reset build options' do - subject - - expect(build.read_attribute(:options)).to be_nil - end - end - end - describe '#invalid_dependencies' do let!(:pre_stage_job_valid) { create(:ci_build, :manual, pipeline: pipeline, name: 'test1', stage_idx: 0) } let!(:pre_stage_job_invalid) { create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test2', stage_idx: 1) } diff --git a/spec/support/shared_examples/ci/deployable_shared_examples.rb b/spec/support/shared_examples/ci/deployable_shared_examples.rb index fc8f947259b724..58b8bf17c02d07 100644 --- a/spec/support/shared_examples/ci/deployable_shared_examples.rb +++ b/spec/support/shared_examples/ci/deployable_shared_examples.rb @@ -310,7 +310,7 @@ describe '#environment_options_for_permanent_storage' do subject { job.environment_options_for_permanent_storage } - let(:job) { described_class.new(options: options) } + let(:job) { FactoryBot.build(factory_type, options: options) } let(:options) do { script: 'script', -- GitLab From 83fafae3f0a5414c6863b0ed4f789b11a03ca26d Mon Sep 17 00:00:00 2001 From: lma-git Date: Wed, 3 Sep 2025 16:06:36 -0700 Subject: [PATCH 2/5] Update resource group and build_metadata Updates EnsureResourceGroups to use temp_job_definition instead of options. Updates Ci::BuildMetadata to only validate config_options if it is not nil. --- app/models/ci/build_metadata.rb | 1 + .../pipeline/chain/ensure_resource_groups.rb | 6 +- spec/models/concerns/ci/metadatable_spec.rb | 162 ++++++++++++++++++ .../ci/create_pipeline_service_spec.rb | 26 ++- 4 files changed, 192 insertions(+), 3 deletions(-) diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb index 92e2210f751fde..474375bb1cbb9a 100644 --- a/app/models/ci/build_metadata.rb +++ b/app/models/ci/build_metadata.rb @@ -69,6 +69,7 @@ def ci_validate_config_options_enabled? def validate_config_options_schema return unless ci_validate_config_options_enabled? + return if config_options.nil? validator = JsonSchemaValidator.new({ filename: 'build_metadata_config_options', diff --git a/lib/gitlab/ci/pipeline/chain/ensure_resource_groups.rb b/lib/gitlab/ci/pipeline/chain/ensure_resource_groups.rb index dbabc0c40f226e..800be782a0aead 100644 --- a/lib/gitlab/ci/pipeline/chain/ensure_resource_groups.rb +++ b/lib/gitlab/ci/pipeline/chain/ensure_resource_groups.rb @@ -18,7 +18,11 @@ def break? def ensure_resource_group(processable) return unless processable.is_a?(::Ci::Processable) - key = processable.options.delete(:resource_group_key) + key = if Feature.enabled?(:read_from_new_ci_destinations, project) && processable.temp_job_definition + processable.temp_job_definition.config.dig(:options, :resource_group_key) + else + processable.options.delete(:resource_group_key) + end resource_group = ::Gitlab::Ci::Pipeline::Seed::Processable::ResourceGroup .new(processable, key).to_resource diff --git a/spec/models/concerns/ci/metadatable_spec.rb b/spec/models/concerns/ci/metadatable_spec.rb index c97a3f7cd52662..612902fe63088d 100644 --- a/spec/models/concerns/ci/metadatable_spec.rb +++ b/spec/models/concerns/ci/metadatable_spec.rb @@ -12,6 +12,168 @@ processable.clear_memoization(:can_write_metadata?) end + describe '#options' do + let(:job) { build(:ci_build, :without_job_definition, metadata: nil) } + let(:legacy_job_options) { { script: 'legacy job' } } + let(:job_definition_options) { { script: 'job_definition' } } + let(:metadata_options) { { script: 'metadata' } } + + subject(:options) { job.options } + + it 'defaults to an empty hash' do + is_expected.to eq({}) + end + + context 'when metadata options are present' do + before do + job.ensure_metadata.write_attribute(:config_options, metadata_options) + end + + it { is_expected.to eq(metadata_options) } + + context 'when job definition options are present' do + before do + job.build_job_definition.write_attribute(:config, { options: job_definition_options }) + end + + it { is_expected.to eq(job_definition_options) } + + context 'when FF `read_from_new_ci_destinations` is disabled' do + before do + stub_feature_flags(read_from_new_ci_destinations: false) + end + + it { is_expected.to eq(metadata_options) } + end + + context 'when legacy job options are present' do + before do + job.write_attribute(:options, legacy_job_options) + end + + it { is_expected.to eq(legacy_job_options) } + end + end + end + end + + describe '#yaml_variables' do + let(:job) { build(:ci_build, :without_job_definition, metadata: nil) } + let(:legacy_job_variables) { [{ key: 'VAR', value: 'legacy job' }] } + let(:job_definition_variables) { [{ key: 'VAR', value: 'job_definition' }] } + let(:metadata_variables) { [{ key: 'VAR', value: 'metadata' }] } + + subject(:yaml_variables) { job.yaml_variables } + + it 'defaults to an empty array' do + is_expected.to eq([]) + end + + context 'when metadata variables are present' do + before do + job.ensure_metadata.write_attribute(:config_variables, metadata_variables) + end + + it { is_expected.to eq(metadata_variables) } + + context 'when job definition variables are present' do + before do + job.build_job_definition.write_attribute(:config, { yaml_variables: job_definition_variables }) + end + + it { is_expected.to eq(job_definition_variables) } + + context 'when FF `read_from_new_ci_destinations` is disabled' do + before do + stub_feature_flags(read_from_new_ci_destinations: false) + end + + it { is_expected.to eq(metadata_variables) } + end + + context 'when legacy job variables are present' do + before do + job.write_attribute(:yaml_variables, legacy_job_variables) + end + + it { is_expected.to eq(legacy_job_variables) } + end + end + end + end + + describe '#options=' do + let(:options) { { script: 'echo test' } } + + subject(:set_options) { processable.options = options } + + before do + processable.write_attribute(:options, { script: 'echo something' }) + end + + it 'does not change metadata.config_options' do + expect { set_options } + .to not_change { processable.metadata.config_options } + end + + it 'does not set legacy job options to nil' do + expect { set_options } + .to not_change { processable.read_attribute(:options) } + end + + context 'when FF `stop_writing_builds_metadata` is disabled' do + before do + stub_feature_flags(stop_writing_builds_metadata: false) + end + + it 'sets value into metadata.config_options' do + expect { set_options } + .to change { processable.metadata.config_options }.to(options) + end + + it 'sets legacy job options to nil' do + expect { set_options } + .to change { processable.read_attribute(:options) }.to(nil) + end + end + end + + describe '#yaml_variables=' do + let(:yaml_variables) { [{ key: 'VAR', value: 'test' }] } + + subject(:set_yaml_variables) { processable.yaml_variables = yaml_variables } + + before do + processable.write_attribute(:yaml_variables, [{ key: 'VAR', value: 'something' }]) + end + + it 'does not change metadata.config_variables' do + expect { set_yaml_variables } + .to not_change { processable.metadata.config_variables } + end + + it 'does not set legacy job yaml_variables to nil' do + expect { set_yaml_variables } + .to not_change { processable.read_attribute(:yaml_variables) } + end + + context 'when FF `stop_writing_builds_metadata` is disabled' do + before do + stub_feature_flags(stop_writing_builds_metadata: false) + end + + it 'sets value into metadata.config_variables' do + expect { set_yaml_variables } + .to change { processable.metadata.config_variables }.to(yaml_variables) + end + + it 'sets legacy job yaml_variables to nil' do + expect { set_yaml_variables } + .to change { processable.read_attribute(:yaml_variables) }.to(nil) + end + end + end + describe '#timeout_human_readable_value' do let_it_be_with_refind(:job) { create(:ci_build) } diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 3046dbd00b9350..adacb54b1b3529 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -789,7 +789,7 @@ def previous_commit_sha_from_ref(ref) end end - context 'with resource group' do + shared_examples 'with resource group' do context 'when resource group is defined' do before do config = YAML.dump( @@ -827,7 +827,9 @@ def previous_commit_sha_from_ref(ref) end end - context 'when resource group is defined for review app deployment' do + it_behaves_like 'with resource group' + + shared_examples 'when resource group is defined for review app deployment' do before do config = YAML.dump( review_app: { @@ -879,6 +881,26 @@ def previous_commit_sha_from_ref(ref) end end + it_behaves_like 'when resource group is defined for review app deployment' + + context 'when FF `stop_writing_builds_metadata` is disabled' do + before do + stub_feature_flags(stop_writing_builds_metadata: false) + end + + it_behaves_like 'with resource group' + it_behaves_like 'when resource group is defined for review app deployment' + + context 'when FF `read_from_new_ci_destinations` is disabled' do + before do + stub_feature_flags(read_from_new_ci_destinations: false) + end + + it_behaves_like 'with resource group' + it_behaves_like 'when resource group is defined for review app deployment' + end + end + context 'with timeout' do context 'when builds with custom timeouts are configured' do before do -- GitLab From c083e728ebbef5a00652d7635856acf3bee883fd Mon Sep 17 00:00:00 2001 From: lma-git Date: Wed, 3 Sep 2025 20:14:20 -0700 Subject: [PATCH 3/5] Update stub_build, ensure_environments, ensure rgs, add FF stubs Update stub_build, ensure_environments, ensure rgs, add FF stubs --- .../environments/create_for_job_service.rb | 6 +++++- .../mutations/dast/profiles/run_spec.rb | 5 +++++ .../app_sec/dast/scans/run_service_spec.rb | 3 +++ .../dast_configuration_spec.rb | 3 +++ .../set_build_sources_spec.rb | 3 +++ .../atomic_processing_service_spec.rb | 6 ++++++ lib/gitlab/ci/build/context/global.rb | 10 +++++++++- .../gitlab/ci/build/context/global_spec.rb | 20 ++++++++++++++++++- spec/lib/gitlab/ci/lint_spec.rb | 8 ++++++++ .../lib/gitlab/ci/pipeline/chain/seed_spec.rb | 6 ++++++ .../api/ci/runner/jobs_request_post_spec.rb | 3 +++ .../ci/lint/result_serializer_spec.rb | 3 +++ .../environment_spec.rb | 3 +++ .../create_web_ide_terminal_service_spec.rb | 3 +++ 14 files changed, 79 insertions(+), 3 deletions(-) diff --git a/app/services/environments/create_for_job_service.rb b/app/services/environments/create_for_job_service.rb index f3b57e4f20b542..1655ed7386824c 100644 --- a/app/services/environments/create_for_job_service.rb +++ b/app/services/environments/create_for_job_service.rb @@ -62,7 +62,11 @@ def cluster_agent_path(job) end def environment_options(job) - job.options&.dig(:environment) || {} + if Feature.enabled?(:read_from_new_ci_destinations, job.project) && job.temp_job_definition + job.temp_job_definition.config.dig(:options, :environment) || {} + else + job.options&.dig(:environment) || {} + end end def matching_authorization(job) diff --git a/ee/spec/graphql/mutations/dast/profiles/run_spec.rb b/ee/spec/graphql/mutations/dast/profiles/run_spec.rb index ff1a68536c5773..3000d3c98662a8 100644 --- a/ee/spec/graphql/mutations/dast/profiles/run_spec.rb +++ b/ee/spec/graphql/mutations/dast/profiles/run_spec.rb @@ -50,6 +50,11 @@ ) end + before do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + end + it 'makes the variable available to the dast build' do subject diff --git a/ee/spec/services/app_sec/dast/scans/run_service_spec.rb b/ee/spec/services/app_sec/dast/scans/run_service_spec.rb index 0f95ed2efe13c1..14e2f0452bd006 100644 --- a/ee/spec/services/app_sec/dast/scans/run_service_spec.rb +++ b/ee/spec/services/app_sec/dast/scans/run_service_spec.rb @@ -108,6 +108,9 @@ end it 'creates a build with appropriate variables' do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + build = pipeline.builds.first expected_variables = [ diff --git a/ee/spec/services/ci/create_pipeline_service/dast_configuration_spec.rb b/ee/spec/services/ci/create_pipeline_service/dast_configuration_spec.rb index c38fdb231903cd..9787c081554049 100644 --- a/ee/spec/services/ci/create_pipeline_service/dast_configuration_spec.rb +++ b/ee/spec/services/ci/create_pipeline_service/dast_configuration_spec.rb @@ -95,6 +95,9 @@ shared_examples 'a missing profile' do it 'communicates failure' do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + expect(subject.error_messages[0].content).to include("DAST profile not found: #{profile.name}") end end diff --git a/ee/spec/services/ci/create_pipeline_service/set_build_sources_spec.rb b/ee/spec/services/ci/create_pipeline_service/set_build_sources_spec.rb index ff51ee133b0402..b06d2980dc39f0 100644 --- a/ee/spec/services/ci/create_pipeline_service/set_build_sources_spec.rb +++ b/ee/spec/services/ci/create_pipeline_service/set_build_sources_spec.rb @@ -118,6 +118,9 @@ end before do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + create(:security_policy, :scan_execution_policy, linked_projects: [project], content: scan_execution_policy.slice(:actions), security_orchestration_policy_configuration: project_configuration) diff --git a/ee/spec/services/ee/ci/pipeline_processing/atomic_processing_service_spec.rb b/ee/spec/services/ee/ci/pipeline_processing/atomic_processing_service_spec.rb index e297b4ba28173b..f4aeef7d9e70db 100644 --- a/ee/spec/services/ee/ci/pipeline_processing/atomic_processing_service_spec.rb +++ b/ee/spec/services/ee/ci/pipeline_processing/atomic_processing_service_spec.rb @@ -342,6 +342,9 @@ end it 'skips all jobs in later stages' do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + process_pipeline expect(pipeline).to be_persisted @@ -376,6 +379,9 @@ end it 'skips all later jobs' do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + process_pipeline expect(pipeline).to be_persisted diff --git a/lib/gitlab/ci/build/context/global.rb b/lib/gitlab/ci/build/context/global.rb index dd0bc54d8b289b..61b4552619f644 100644 --- a/lib/gitlab/ci/build/context/global.rb +++ b/lib/gitlab/ci/build/context/global.rb @@ -26,9 +26,17 @@ def variables private def stub_build - ::Ci::Build.new(build_attributes) + if Feature.enabled?(:read_from_new_ci_destinations, project) + # We can associate job_definition directly because this job isn't persisted + ::Ci::Build.new(pipeline_attributes).tap do |job| + job.build_job_definition(config: { yaml_variables: @yaml_variables }) + end + else + ::Ci::Build.new(build_attributes) + end end + # Remove this method with FF `read_from_new_ci_destinations` def build_attributes pipeline_attributes.merge( yaml_variables: @yaml_variables) diff --git a/spec/lib/gitlab/ci/build/context/global_spec.rb b/spec/lib/gitlab/ci/build/context/global_spec.rb index 47b08132c664f1..55ad1d55ccaa11 100644 --- a/spec/lib/gitlab/ci/build/context/global_spec.rb +++ b/spec/lib/gitlab/ci/build/context/global_spec.rb @@ -15,11 +15,29 @@ it { is_expected.not_to have_key('CI_JOB_NAME') } - context 'with passed yaml variables' do + shared_examples 'with passed yaml variables' do let(:yaml_variables) { [{ key: 'SUPPORTED', value: 'parsed', public: true }] } it { is_expected.to include('SUPPORTED' => 'parsed') } end + + it_behaves_like 'with passed yaml variables' + + context 'when FF `stop_writing_builds_metadata` is disabled' do + before do + stub_feature_flags(stop_writing_builds_metadata: false) + end + + it_behaves_like 'with passed yaml variables' + + context 'when FF `read_from_new_ci_destinations` is disabled' do + before do + stub_feature_flags(read_from_new_ci_destinations: false) + end + + it_behaves_like 'with passed yaml variables' + end + end end describe '#variables' do diff --git a/spec/lib/gitlab/ci/lint_spec.rb b/spec/lib/gitlab/ci/lint_spec.rb index bdc4fbaf5868ff..f826e6cf1a7ad9 100644 --- a/spec/lib/gitlab/ci/lint_spec.rb +++ b/spec/lib/gitlab/ci/lint_spec.rb @@ -43,6 +43,9 @@ end it 'returns a valid result', :aggregate_failures do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + expect(subject).to be_valid expect(subject.errors).to be_empty @@ -1026,6 +1029,11 @@ it_behaves_like 'content with errors and warnings' it_behaves_like 'content is valid' do + before do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + end + it 'does not include extra attributes' do subject.jobs.each do |job| expect(job.key?(:only)).to be_falsey diff --git a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb index a8358f3910dc1c..febc53e48290cb 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb @@ -201,6 +201,9 @@ let(:rspec_variables) { command.pipeline_seed.stages[0].statuses[0].variables.to_hash } it 'sends root variable with overridden by rules' do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + run_chain expect(rspec_variables['VAR1']).to eq('overridden var 1') @@ -223,6 +226,9 @@ let(:rspec_variables) { command.pipeline_seed.stages[0].statuses[0].variables.to_hash } it 'correctly parses rule variables' do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + run_chain expect(rspec_variables['SYMBOL']).to eq("symbol") diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb index 775e051285fbc8..c0e829a72edcea 100644 --- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb +++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb @@ -1334,6 +1334,9 @@ def request_job(token = runner.token, **params) end before do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + stub_webide_config_file(config_content) project.add_maintainer(user) diff --git a/spec/serializers/ci/lint/result_serializer_spec.rb b/spec/serializers/ci/lint/result_serializer_spec.rb index a99e3901ed566d..411c0185415247 100644 --- a/spec/serializers/ci/lint/result_serializer_spec.rb +++ b/spec/serializers/ci/lint/result_serializer_spec.rb @@ -77,6 +77,9 @@ end it 'returns job data' do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + expect(first_job[:name]).to eq('rspec') expect(first_job[:stage]).to eq('test') expect(first_job[:before_script]).to eq(['bundle install', 'bundle exec rake db:create']) diff --git a/spec/services/ci/create_pipeline_service/environment_spec.rb b/spec/services/ci/create_pipeline_service/environment_spec.rb index 0df80b8a9de36d..6c7fbc866eed44 100644 --- a/spec/services/ci/create_pipeline_service/environment_spec.rb +++ b/spec/services/ci/create_pipeline_service/environment_spec.rb @@ -56,6 +56,9 @@ let(:tier) { 'testing' } it 'creates the environment with the expected tier' do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + is_expected.to be_created_successfully expect(Environment.find_by_name("review/master")).to be_testing diff --git a/spec/services/ci/create_web_ide_terminal_service_spec.rb b/spec/services/ci/create_web_ide_terminal_service_spec.rb index 698146375dfbc0..85b7cb708e47a6 100644 --- a/spec/services/ci/create_web_ide_terminal_service_spec.rb +++ b/spec/services/ci/create_web_ide_terminal_service_spec.rb @@ -44,6 +44,9 @@ context 'when web-ide has valid configuration' do before do + # TODO: Remove this stub when resolving https://gitlab.com/gitlab-org/gitlab/-/issues/567952 + stub_feature_flags(stop_writing_builds_metadata: false) + stub_webide_config_file(config_content) end -- GitLab From 93a87ed8a4f7d37b9dfc1ae0e2069a258aa311be Mon Sep 17 00:00:00 2001 From: lma-git Date: Mon, 8 Sep 2025 16:41:51 -0700 Subject: [PATCH 4/5] Update read_metadata_attribute to read from temp job def Updates read_metadata_attribute to also read from temp_job_definition if it exists. Updates global context to use the temp_job_definition fabricator instead. --- app/models/concerns/ci/metadatable.rb | 13 ++- .../environments/create_for_job_service.rb | 6 +- lib/gitlab/ci/build/context/global.rb | 8 +- .../pipeline/chain/ensure_resource_groups.rb | 4 +- spec/models/concerns/ci/metadatable_spec.rb | 96 ++++++++++++------- 5 files changed, 81 insertions(+), 46 deletions(-) diff --git a/app/models/concerns/ci/metadatable.rb b/app/models/concerns/ci/metadatable.rb index f5851b601eb6fc..32bd6a6e094cb1 100644 --- a/app/models/concerns/ci/metadatable.rb +++ b/app/models/concerns/ci/metadatable.rb @@ -193,10 +193,15 @@ def exit_code=(value) private def read_metadata_attribute(legacy_key, metadata_key, job_definition_key, default_value = nil) - (legacy_key && read_attribute(legacy_key)) || - (read_from_new_destination? && job_definition && job_definition.config[job_definition_key]) || - metadata&.read_attribute(metadata_key) || - default_value + result = read_attribute(legacy_key) if legacy_key + return result if result + + if read_from_new_destination? + result = job_definition&.config&.dig(job_definition_key) || temp_job_definition&.config&.dig(job_definition_key) + return result if result + end + + metadata&.read_attribute(metadata_key) || default_value end def write_metadata_attribute(legacy_key, metadata_key, value) diff --git a/app/services/environments/create_for_job_service.rb b/app/services/environments/create_for_job_service.rb index 1655ed7386824c..f3b57e4f20b542 100644 --- a/app/services/environments/create_for_job_service.rb +++ b/app/services/environments/create_for_job_service.rb @@ -62,11 +62,7 @@ def cluster_agent_path(job) end def environment_options(job) - if Feature.enabled?(:read_from_new_ci_destinations, job.project) && job.temp_job_definition - job.temp_job_definition.config.dig(:options, :environment) || {} - else - job.options&.dig(:environment) || {} - end + job.options&.dig(:environment) || {} end def matching_authorization(job) diff --git a/lib/gitlab/ci/build/context/global.rb b/lib/gitlab/ci/build/context/global.rb index 61b4552619f644..09fab5e7ed6984 100644 --- a/lib/gitlab/ci/build/context/global.rb +++ b/lib/gitlab/ci/build/context/global.rb @@ -27,9 +27,13 @@ def variables def stub_build if Feature.enabled?(:read_from_new_ci_destinations, project) - # We can associate job_definition directly because this job isn't persisted ::Ci::Build.new(pipeline_attributes).tap do |job| - job.build_job_definition(config: { yaml_variables: @yaml_variables }) + temp_job_definition = ::Ci::JobDefinition.fabricate( + config: { yaml_variables: @yaml_variables }, + project_id: pipeline.project_id, + partition_id: pipeline.partition_id + ) + job.temp_job_definition = temp_job_definition end else ::Ci::Build.new(build_attributes) diff --git a/lib/gitlab/ci/pipeline/chain/ensure_resource_groups.rb b/lib/gitlab/ci/pipeline/chain/ensure_resource_groups.rb index 800be782a0aead..3f510044b8b7d7 100644 --- a/lib/gitlab/ci/pipeline/chain/ensure_resource_groups.rb +++ b/lib/gitlab/ci/pipeline/chain/ensure_resource_groups.rb @@ -18,8 +18,8 @@ def break? def ensure_resource_group(processable) return unless processable.is_a?(::Ci::Processable) - key = if Feature.enabled?(:read_from_new_ci_destinations, project) && processable.temp_job_definition - processable.temp_job_definition.config.dig(:options, :resource_group_key) + key = if Feature.enabled?(:read_from_new_ci_destinations, project) + processable.options[:resource_group_key] else processable.options.delete(:resource_group_key) end diff --git a/spec/models/concerns/ci/metadatable_spec.rb b/spec/models/concerns/ci/metadatable_spec.rb index 612902fe63088d..855fca28ace199 100644 --- a/spec/models/concerns/ci/metadatable_spec.rb +++ b/spec/models/concerns/ci/metadatable_spec.rb @@ -16,6 +16,7 @@ let(:job) { build(:ci_build, :without_job_definition, metadata: nil) } let(:legacy_job_options) { { script: 'legacy job' } } let(:job_definition_options) { { script: 'job_definition' } } + let(:temp_job_definition_options) { { script: 'temp_job_definition' } } let(:metadata_options) { { script: 'metadata' } } subject(:options) { job.options } @@ -31,27 +32,36 @@ it { is_expected.to eq(metadata_options) } - context 'when job definition options are present' do + context 'when temp job definition options are present' do before do - job.build_job_definition.write_attribute(:config, { options: job_definition_options }) + temp_job_definition = build(:ci_job_definition, config: { options: temp_job_definition_options }) + job.write_attribute(:temp_job_definition, temp_job_definition) end - it { is_expected.to eq(job_definition_options) } + it { is_expected.to eq(temp_job_definition_options) } - context 'when FF `read_from_new_ci_destinations` is disabled' do + context 'when job definition options are present' do before do - stub_feature_flags(read_from_new_ci_destinations: false) + job.build_job_definition.write_attribute(:config, { options: job_definition_options }) end - it { is_expected.to eq(metadata_options) } - end + it { is_expected.to eq(job_definition_options) } - context 'when legacy job options are present' do - before do - job.write_attribute(:options, legacy_job_options) + context 'when FF `read_from_new_ci_destinations` is disabled' do + before do + stub_feature_flags(read_from_new_ci_destinations: false) + end + + it { is_expected.to eq(metadata_options) } end - it { is_expected.to eq(legacy_job_options) } + context 'when legacy job options are present' do + before do + job.write_attribute(:options, legacy_job_options) + end + + it { is_expected.to eq(legacy_job_options) } + end end end end @@ -61,6 +71,7 @@ let(:job) { build(:ci_build, :without_job_definition, metadata: nil) } let(:legacy_job_variables) { [{ key: 'VAR', value: 'legacy job' }] } let(:job_definition_variables) { [{ key: 'VAR', value: 'job_definition' }] } + let(:temp_job_definition_variables) { [{ key: 'VAR', value: 'temp_job_definition' }] } let(:metadata_variables) { [{ key: 'VAR', value: 'metadata' }] } subject(:yaml_variables) { job.yaml_variables } @@ -76,27 +87,36 @@ it { is_expected.to eq(metadata_variables) } - context 'when job definition variables are present' do + context 'when temp job definition variables are present' do before do - job.build_job_definition.write_attribute(:config, { yaml_variables: job_definition_variables }) + temp_job_definition = build(:ci_job_definition, config: { yaml_variables: temp_job_definition_variables }) + job.write_attribute(:temp_job_definition, temp_job_definition) end - it { is_expected.to eq(job_definition_variables) } + it { is_expected.to eq(temp_job_definition_variables) } - context 'when FF `read_from_new_ci_destinations` is disabled' do + context 'when job definition variables are present' do before do - stub_feature_flags(read_from_new_ci_destinations: false) + job.build_job_definition.write_attribute(:config, { yaml_variables: job_definition_variables }) end - it { is_expected.to eq(metadata_variables) } - end + it { is_expected.to eq(job_definition_variables) } - context 'when legacy job variables are present' do - before do - job.write_attribute(:yaml_variables, legacy_job_variables) + context 'when FF `read_from_new_ci_destinations` is disabled' do + before do + stub_feature_flags(read_from_new_ci_destinations: false) + end + + it { is_expected.to eq(metadata_variables) } end - it { is_expected.to eq(legacy_job_variables) } + context 'when legacy job variables are present' do + before do + job.write_attribute(:yaml_variables, legacy_job_variables) + end + + it { is_expected.to eq(legacy_job_variables) } + end end end end @@ -497,6 +517,7 @@ describe '#id_tokens' do let(:metadata_id_tokens) { { 'TEST_ID_TOKEN' => { 'aud' => 'https://metadata' } } } let(:job_definition_id_tokens) { { 'TEST_ID_TOKEN' => { 'aud' => 'https://job.definition' } } } + let(:temp_job_definition_id_tokens) { { 'TEST_ID_TOKEN' => { 'aud' => 'https://temp.job.definition' } } } subject(:id_tokens) { processable.id_tokens } @@ -515,26 +536,35 @@ expect(processable.id_tokens?).to be(true) end - context 'when job definition id_tokens are present' do + context 'when temp job definition id_tokens are present' do before do - updated_config = processable.job_definition.config.merge(id_tokens: job_definition_id_tokens) - processable.job_definition.write_attribute(:config, updated_config) + temp_job_definition = build(:ci_job_definition, config: { id_tokens: temp_job_definition_id_tokens }) + processable.write_attribute(:temp_job_definition, temp_job_definition) end - it 'returns job definition id_tokens' do - expect(id_tokens).to eq(job_definition_id_tokens) - expect(processable.id_tokens?).to be(true) - end + it { is_expected.to eq(temp_job_definition_id_tokens) } - context 'when FF `read_from_new_ci_destinations` is disabled' do + context 'when job definition id_tokens are present' do before do - stub_feature_flags(read_from_new_ci_destinations: false) + updated_config = processable.job_definition.config.merge(id_tokens: job_definition_id_tokens) + processable.job_definition.write_attribute(:config, updated_config) end - it 'returns metadata id_tokens' do - expect(id_tokens).to eq(metadata_id_tokens) + it 'returns job definition id_tokens' do + expect(id_tokens).to eq(job_definition_id_tokens) expect(processable.id_tokens?).to be(true) end + + context 'when FF `read_from_new_ci_destinations` is disabled' do + before do + stub_feature_flags(read_from_new_ci_destinations: false) + end + + it 'returns metadata id_tokens' do + expect(id_tokens).to eq(metadata_id_tokens) + expect(processable.id_tokens?).to be(true) + end + end end end end -- GitLab From a357361d415b72213ad40a018d40ce54631d313e Mon Sep 17 00:00:00 2001 From: lma-git Date: Mon, 8 Sep 2025 20:20:05 -0700 Subject: [PATCH 5/5] Fix ensure_resource_groups_spec tests --- .../chain/ensure_resource_groups_spec.rb | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb index ddd7796cba36d4..c31eb5f31ee87e 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb @@ -32,6 +32,12 @@ expect(project.resource_groups.find_by_key('production')).to be_present expect(job.resource_group.key).to eq('production') + end + + it 'deletes :resource_group_key from options when FF `read_from_new_ci_destinations` is disabled' do + stub_feature_flags(read_from_new_ci_destinations: false) + subject + expect(job.options[:resource_group_key]).to be_nil end @@ -45,6 +51,12 @@ expect(project.resource_groups.find_by_key('production')).to be_present expect(job.resource_group.key).to eq('production') + end + + it 'deletes :resource_group_key from options when FF `read_from_new_ci_destinations` is disabled' do + stub_feature_flags(read_from_new_ci_destinations: false) + subject + expect(job.options[:resource_group_key]).to be_nil end end @@ -73,6 +85,12 @@ it 'always expands the single layer of variables' do expect { subject }.to change { Ci::ResourceGroup.count }.by(1) expect(project.resource_groups.find_by_key('TE_GROUP')).to be_present + end + + it 'deletes :resource_group_key from options when FF `read_from_new_ci_destinations` is disabled' do + stub_feature_flags(read_from_new_ci_destinations: false) + subject + expect(job.options[:resource_group_key]).to be_nil end end @@ -83,6 +101,12 @@ it 'expands all of the nested variables before creating the group' do expect { subject }.to change { Ci::ResourceGroup.count }.by(1) expect(project.resource_groups.find_by_key('TEST_GROUP')).to be_present + end + + it 'deletes :resource_group_key from options when FF `read_from_new_ci_destinations` is disabled' do + stub_feature_flags(read_from_new_ci_destinations: false) + subject + expect(job.options[:resource_group_key]).to be_nil end end -- GitLab