Skip to content

Refactor pipeline execution policy stages injection

We should refactor the stages injection logic and place them under Gitlab::Ci::Config (!178199 (comment 2332013877)):

These 3 classes should be all placed closely together and be agnostic from Pipeline Execution Policy:

  • Gitlab::Ci::Config::EdgeStagesInjector
  • Gitlab::Ci::Config::ReservedStagesInjector
  • Gitlab::Ci::Config::StagesMerger

I think we need to keep generic concepts inside the Gitlab::Ci::Config so they can become reusable building blocks and more encouraged to working together cohesively. Since these classes modify the internal config structure, they should be owned by CI.

Further feedback to consider (!178199 (comment 2326225590)):

def enforce_pipeline_execution_policy_stages(config)
  pipeline_policy_context&.enforce_stages!(config: config, raise_error: ::Gitlab::Ci::Config::ConfigError)
end

# in pipeline_policy_context
def enforce_stages(config:, raise_error:)
  # ... 
rescue ::Gitlab::Ci::Pipeline::PipelineExecutionPolicies::CustomStagesInjector::InvalidStageConditionError => e
  raise raise_error, e.message
end

This should allow us to:

  1. Keep all the logic inside pipeline_policy_context and not leaking into CI
  2. Make Ci::Config agnostic of downstream exceptions
  3. Have less complexity here.

The general theme is that we should keep most of the logic and state inside pipeline_policy_context with regards to PEP. The CI code should simply call high-level methods.

Later we can breakdown pipeline_policy_context into smaller classes. Ideally I would like us to invert the dependencies more like a plug-in system:

  1. A Plugin PipelineExecutionPolicy is registered in Ci::CreatePipelineService1.
  2. The plugin component defines callback methods based on a supported list of callbacks.
  3. The logic in Ci::CreatePipelineService fires callbacks to registered plugins, passing data to each callback.
  4. The plugin can modify the pipeline data structure along the way.
Edited by Martin Čavoj