Skip to main content

Adding Pipeline Steps

Adding Pipeline Steps

Internal Extension

Introduce one pipeline responsibility without weakening registration, ordering, composition, or failure contracts.

Commandapp/core/pipeline/steps/

Category

Developer Guide

Quick Command

implement -> export -> register -> order -> compose -> test

BaseStepStepRegistrySTEP_ORDERprofiles

Overview

A pipeline step is a small adapter executed with one shared GitContext. Most active steps delegate one operation to the workflow engine; they do not reimplement Git, changelog, backup, cleanup, or release logic inside the step.


Implement One Responsibility

Minimal step shape
python
from app.core.pipeline.steps.base_step import BaseStep

class PublishReportStep(BaseStep):
"""Delegate report publication to the workflow engine."""

  def execute(self, context) -> None:
      """Publish the prepared report for the active workflow."""
      context.engine.publish_report()

Use constructor arguments only when the resolved step definition truly needs per-step data. Put shared runtime state on GitContext and domain behavior in a focused service or the workflow engine.


Wire the Step Through the System

Workflow Timeline

1
Implement the class
Add a documented BaseStep subclass under app/core/pipeline/steps with one clear execute(context) responsibility.
completed
2
Export the class
Expose it through the appropriate steps package __init__.py so the registration module can import it.
completed
3
Register a unique name
Add the class to register_all_steps() in app/core/pipeline/step_registry.py.
current
4
Assign global priority
Add the same registered name to STEP_ORDER at the safe phase boundary.
pending
5
Compose intentional profiles
Add the name only to PIPELINE_PROFILES flows that require the behavior.
pending
6
Test and document
Cover delegation, registry, profile expansion, ordering, failures, side effects, and changed user behavior.
pending

Preserve Name Consistency

The same exact string connects three active definitions:

  1. StepRegistry.register("publish_report_step", PublishReportStep);
  2. {"name": "publish_report_step"} inside a profile; and
  3. "publish_report_step": <priority> inside STEP_ORDER.

An unregistered name fails during pipeline construction. A registered step without a profile entry never runs. A step omitted from STEP_ORDER receives fallback priority 999 during merged-profile composition and moves behind all known steps.



Testing Checklist

Before You Begin

  • Step delegationRequired

    A focused unit test verifies execute(context) calls the intended engine or service method once with the right arguments.

  • Registry constructionRequired

    The registered name resolves to the intended class and unknown names still fail clearly.

  • Profile membershipRequired

    Only intentional profiles contain the new name and expansion produces the expected sequence.

  • Merged orderingRequired

    Composition with overlapping profiles deduplicates the step and places it at the intended global priority.

  • Failure behaviorRequired

    An exception stops later steps, preserves useful context, and does not imply rollback of earlier effects.

  • Integration effectsRequired

    Use temporary repositories or mocked boundaries for any file, Git, subprocess, or remote behavior.


Public Profile Changes

If the goal is a new public custy run PROFILE value, the change is larger than adding one step. Review the typed StepChoices CLI enum, Run option help, resolver profile, exact sequence, safety behavior, examples, configuration, integration tests, and command documentation. Internal helper profiles should remain internal unless a stable user contract is deliberately designed.


Continue