Lesson 43 of 45 intermediate

CI/CD Pipelines

Build and test every push automatically, and release the same artifact through each environment

Guess first

Pick an answer. You will see if you were right at the end of the lesson.

What does continuous integration do?

Open interactive version (quiz + challenge)

Real-world analogy

A bakery has a checkpoint at the end of the oven line. Every tray goes through the same steps, and a tray that fails the taste test never reaches the shop. The boxed bread that passed is the same bread sent to every shop, and nobody rebakes it on the way. The line is the pipeline, the taste test is the automated tests, and the boxed bread is the build artifact.

What is it?

CI/CD automates the path from a git push to a running release. CI (continuous integration) builds the code and runs the tests on every push. CD (continuous delivery or deployment) takes a build that passed and releases it through environments. A pipeline is a file in the repo that lists jobs and steps, such as a GitHub Actions YAML workflow. Good pipelines fail fast and keep secrets out of logs. They build the artifact once, so the thing you tested is the thing you ship.

Real-world relevance

A team used to deploy by copying files from a laptop on Friday evenings. One release shipped a half-finished change that nobody had tested, and the weekend went on the rollback. After moving to a pipeline, every merge to main builds, tests and produces an image. Deploying that image to staging is one click. Developers still own the tests and the Dockerfile, and the DevOps team owns the servers and the deploy tooling.

Key points

Quick check

Answer from memory — scrolling up first makes it stick less.

Why build the artifact once and promote the same one through environments?

In the workflow, why does the docker-image job say needs: build-test?

Code example

name: ci
on:
  push:
    branches: [main]
  pull_request:

jobs:
  build-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-dotnet@v6
        with:
          dotnet-version: 10.0.x
      - run: dotnet restore
      - run: dotnet build --no-restore -c Release
      - run: dotnet test --no-build -c Release

  docker-image:
    needs: build-test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: docker build -t shop-api:${{ github.sha }} .

Line-by-line walkthrough

  1. 1. This is a GitHub Actions workflow file. It assumes one solution file at the repo root and a Dockerfile there. The workflow runs on pushes to main and on pull requests.
  2. 2. The build-test job runs on a fresh Ubuntu machine. It checks out the code and installs the .NET 10 SDK with setup-dotnet.
  3. 3. The steps run in order: restore, build in Release mode, then test. If a step fails, the job stops and later steps do not run.
  4. 4. The docker-image job has needs: build-test, so it starts only after build-test succeeds.
  5. 5. The if line limits it to pushes on main. Pull requests are built and tested, but they do not produce an image.
  6. 6. docker build tags the image with the commit SHA, so each image can be traced to one commit. This workflow builds the image but does not push or deploy it.

Spot the bug

on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: dotnet test
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: ./deploy.sh
Need a hint?
Do two jobs in a workflow wait for each other by default?
Show answer
Jobs run in parallel unless one declares needs. The deploy job starts at the same time as the tests, so it deploys even when the tests fail. Fix: add needs: test to the deploy job, so it runs only after the tests pass.

Explain like I'm 5

Every time a child adds a block to a tower, a helper checks that the tower still stands. If it falls, the helper shouts at once. Only a tower that stood is shown to the visitors.

Fun fact

The term continuous integration was popularised by Kent Beck's Extreme Programming in the late 1990s. At that time, teams often merged work only once every few weeks, and the merge itself was a project.

Hands-on challenge

Say it out loud in 30 seconds: "Walk me through a CI/CD pipeline for a .NET API." Then check: did you mention restore, build and test in order, failing fast, publishing one artifact or image, secrets kept in the CI system, approvals for production, and a rollback plan?

More resources

Open interactive version (quiz + challenge) Download the whole course as PDF / Word

Lock it in

← Back to course: .NET + React Playbook