ssprkd.io
CI/CD & Delivery Pipelines
Lesson 1 of 7

Pipeline anatomy

Turn every commit into a tested artifact that ships itself — the build, test, and deploy stages, why they run as gates, and how caching and build-once-promote keep the pipeline fast and honest.

Watch

Speed
📖 Read this walkthrough — every command, and why
Pipeline anatomy — stages that gate on their exit code

Mental model: a CI/CD pipeline is a set of automated stages that a commit triggers, so no
one ships code by clicking through steps by hand. The stages run strictly in order —
lint -> build -> test -> package -> deploy — and the whole engine hinges on one idea:
each stage GATES on its exit code. Exit 0 means pass, and only then does the next stage
start. A stage that exits non-zero stops the pipeline right there, before deploy is ever
reached. That is why broken code physically cannot ship: the guardrail is the exit code.

Vocabulary (say these precisely):
    stage  — a phase of the pipeline, like build or test.
    step   — an individual command inside a stage.
    job    — a unit of work a runner executes.
    runner — the machine (a.k.a. agent) that actually runs the commands.

1 · The staged pipeline, passing (real output)
    ./pipeline.sh          # lint -> build -> test -> package
      == lint ==
      lint OK
      == build ==
      build OK -> build.out
      == test ==
      test OK (artifact present)
      == package ==
      packaged app.tgz
      PIPELINE PASSED (exit 0)
      final exit code: 0
    Read it top to bottom: each "== name ==" header is a stage; each stage passed (exit 0),
    so the next one ran. The final exit code of 0 is the whole pipeline reporting success.

2 · The gate in action — a failing stage stops it before deploy (real output)
    # the test stage fails, so it exits non-zero
      running tests...
      TESTS FAILED -> gate blocks; deploy is NOT reached
      pipeline exit code: 1 (non-zero = release blocked)
    The test stage exited non-zero, the pipeline halted, and deploy never ran. Overall exit
    code 1 = release blocked. This behavior — stop on the first failure, never run what comes
    after — is called fail-fast.

3 · What each part does
    exit 0        stage passed; the next stage is allowed to start.
    exit non-zero stage failed; the pipeline stops here and reports failure.
    fail-fast     because a failing stage blocks everything after it, bad code can't reach deploy.
    the header    "== lint ==" / "== build ==" etc. marks the boundary between stages.

4 · CI vs CD — the two halves
    CI (continuous integration) — the integrate-and-test half: lint, build, and test on
       EVERY change, so regressions are caught as code lands.
    CD (continuous delivery/deployment) — the delivery half: package the artifact and deploy it.
       Continuous DELIVERY stops at a manual release gate; continuous DEPLOYMENT ships every
       passing change automatically.
    In the run above: lint -> build -> test is CI; package -> deploy is CD.

Notes:
    - The pipeline is triggered by a commit — you don't run stages by hand.
    - Order matters: lint -> build -> test -> package -> deploy, each gating the next.
    - "Pass" is defined by the exit code, not by log text. Exit 0 = pass, anything else = fail.
    - A job runs on a runner (agent); steps are the commands inside a stage's job.

Gotchas:
    - A stage that "prints success" but exits non-zero still fails the gate — trust the exit
      code, not the words on screen.
    - Don't put deploy before test. If any earlier stage can be skipped past a failure, the
      guardrail is gone and broken code ships.
    - A non-zero exit anywhere before deploy blocks deploy entirely — that is the point, not a bug.

Verify:
    ./pipeline.sh; echo "final exit: $?"
      # PIPELINE PASSED (exit 0) ... final exit: 0
    Force a failing stage (e.g. break a test) and re-run: the pipeline stops at that stage,
    deploy is not reached, and the final exit code is 1.