WEEK 11Wednesday

CI/CD and Continuous Deployment

Week 11 · From a pull request to production, on Project Pulse

WEEK 11Wednesday

Two teams, one repository

Team 1: four unhappy developers on month-long branches merge into main at once, and main explodes. Team 2: four happy developers on short branches merge every day; a small fire on main is put out with an extinguisher

Ask the room

Same people, same project. Which team would you rather be on?

WEEK 11Wednesday

A small breakdown every Tuesday

"Instead of heading for a big integration breakdown, I decided to have a small breakdown every Tuesday evening."

Adapted from Graham Parke, No Hope for Gomez!

Key point

Integration should be a routine, not a drama.

WEEK 11Wednesday

Knight Capital, 1 August 2012

  • A technician copies new code to the order router's servers and misses one of eight
  • The eighth still holds Power Peg, code unused since 2003
  • The new code reuses Power Peg's old flag
  • The flag goes live: 4 million executions, 397 million shares, about 45 minutes
  • More than $460 million lost
WEEK 11Wednesday

More pull requests, same hours

The agent

An agent multiplies the pull requests your team produces. It doesn't multiply the hours anyone has to review them.

Key point

The pipeline is the one reviewer that checks every pull request the same way.

WEEK 11Wednesday

Continuous integration is a habit

  • Merge small changes, at least daily
  • Every change runs the same checks
  • A red main gets fixed before anything else
Key point

Actions configured and three-week branches is not CI.

WEEK 11Wednesday

Every pull request, checked

A developer opens a pull request on GitHub. GitHub triggers GitHub Actions, which builds, tests, and analyzes the code on a fresh runner and reports pass or fail on the pull request

WEEK 11Wednesday

What gets shipped

  • Source code goes in
  • ./mvnw package builds one executable JAR: your classes, every dependency, an embedded Tomcat
  • Project Pulse also builds the Vue frontend into that same JAR
  • java -jar starts it anywhere Java 21 is installed
WEEK 11Wednesday

It works on my machine

Two machines, a laptop and a production server, each with hardware, a host operating system, and a container engine; the same Project Pulse container, holding the JAR and Java 21, runs on both

"It works on my machine." "Fine, then we'll ship your machine." That's a container.

WEEK 11Wednesday

Image and container

Image

A read-only template. Like a class.

Container

A running instance. Like an object.

Key point

The image is the artifact the pipeline ships.

WEEK 11Wednesday

GitHub Actions in five words

classDiagram
    direction LR
    Repository "1" --> "0..*" Workflow : holds
    Event "1..*" --> "0..*" Workflow : triggers
    Workflow "1" *-- "1..*" Job
    Job "1" *-- "1..*" Step
    Job "1" --> "1" Runner : runs on
WEEK 11Wednesday

Project Pulse: maven-build.yml

on:
  pull_request:
    branches: [main]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11d5960a...   # v4.4.0
      - uses: actions/setup-java@cf277c60... # v4.9.1
        with: { java-version: "21", distribution: "temurin", cache: maven }
      - run: mvn --batch-mode verify
        working-directory: ./backend
  frontend:   # npm ci, ESLint, type check, Prettier
  dockerfile: # Hadolint
Ask the room

Point at the event, a job, a step that uses an action, and a step that runs a command.

WEEK 11Wednesday

The runner starts empty

  • No local database
  • No file you forgot to commit
  • No library you installed by hand last month
Key point

Red in CI and green in your IDE means CI found something real.

WEEK 11Wednesday

Keep it fast

  • Three jobs in parallel: the slowest sets the wait
  • Wait half an hour, and people stop waiting
  • Aim for Extreme Programming's ten-minute build
WEEK 11Wednesday

Two workflows, one path

flowchart LR
    pr["Pull request"] --> ci["maven-build.yml<br/>build · frontend · dockerfile"]
    ci -->|"all green, up to date"| main["Merge to main"]
    main --> build["azure-webapps-deploy.yml<br/>image tagged with the SHA"]
    build --> deploy["staging slot"]
    deploy -->|"a person swaps"| prod["production slot"]
WEEK 11Wednesday

The checks ran. Nothing listened.

  • Every pull request ran build, frontend, and dockerfile
  • No ruleset on main: Merge stayed clickable next to a red X
  • After merge, the deploy built with -DskipTests
  • Trusting tests that might never have passed
Pitfall

Project Pulse, until 3 November 2026.

WEEK 11Wednesday

Demo: the gate

Project Pulse pull request #108: build is still running and marked Required, six checks have passed, and the Merge pull request button is grayed out with the message "Merging is blocked due to pending merge requirements"

WEEK 11Wednesday

Protect main

Rule What it stops
Restrict deletions Deleting main
Block force pushes Rewriting history; a released SHA always exists
Require a pull request Pushing around the checks
Require status checks: build, frontend, dockerfile Merging red or still running
Require branches up to date Merging what was tested against an old main
WEEK 11Wednesday

Leave the bypass list empty

Key point

A gate the maintainer can walk around is not a gate.

"I'll just bypass it this once." Famous last words, and a famous first incident report.

WEEK 11Wednesday

Green alone, broken together

  • Monday: your pull request goes green against Monday's main
  • Tuesday: a teammate merges something else
  • Your green check tested a main that no longer exists
  • Both changes pass alone and break together
Key point

Require branches to be up to date: the checks rerun on what will actually merge.

WEEK 11Wednesday

Know what each check checks

- name: ESLint (report only)
  continue-on-error: true
  run: npm run lint:check
Pitfall

Required "frontend" blocks a broken npm ci, and nothing else yet.

WEEK 11Wednesday

Flaky checks destroy the gate

  • A test fails at random
  • Everyone learns to press Re-run
  • A real failure gets re-run too

"It passed on the third try" is not a test result. It's a slot machine.

WEEK 11Wednesday

CD means two things

What's automatic Who decides production
Continuous integration Build and test every change Not about production
Continuous delivery Every green merge becomes a release that could ship A person presses the button
Continuous deployment Every green merge ships The pipeline
WEEK 11Wednesday

Every merge, deployed

A developer merges a pull request; GitHub triggers GitHub Actions, which builds once, tags the image with the commit SHA, and deploys to the cloud, for Project Pulse the staging slot

WEEK 11Wednesday

Project Pulse does both

To staging

Every merge to main, automatically.

Continuous deployment.

To production

When a person swaps the slots.

Continuous delivery.

Ask the room

Which would you want for your client's MVP, and why?

WEEK 11Wednesday

Build once, promote that build

tags: ghcr.io/${{ env.REPO }}:${{ github.sha }}
  • The image is built once, tagged with the commit SHA
  • Staging runs that image; the swap moves that same image
  • Nothing is rebuilt for production
Key point

A rebuild is a new artifact nobody tested.

WEEK 11Wednesday

When is -DskipTests safe?

Ask the room

The deploy workflow skips the tests. When is that OK?

Key point

Only when the tests passed on exactly the code being merged: required, and up to date.

WEEK 11Wednesday

Bad changes ship fast too

  • 18 November 2025: a permissions change makes a query return duplicates
  • A generated config file doubles; it passes a hardcoded limit of 200 (normal: about 60)
  • Rust code calls unwrap() on the error; the proxy panics
  • The file is "rapidly propagated across the network"
  • Errors from 11:20 UTC; normal again at 17:06

"Hardening ingestion of Cloudflare-generated configuration files in the same way we would for user-generated input."

WEEK 11Wednesday

Deploy to staging, then swap

GitHub Actions deploys the new build to the staging slot while users keep using production; each slot keeps its own database; the slots swap with no downtime, and swapping again brings back the last known good build

WEEK 11Wednesday

Each slot keeps its own database

  • Database address and password live in Azure Key Vault
  • SPRING_PROFILES_ACTIVE picks application-staging.yml or application-prod.yml
  • AZURE_KEY_VAULT_ENDPOINT picks the vault
  • Both are deployment slot settings: they stay with the slot, not the code
WEEK 11Wednesday

Rolling back

Code

Swap back. Seconds. No rebuild.

Data

Migrations run forward only. The old build meets the new schema.

Key point

A schema change the previous build can't live with is a release you can't roll back.

WEEK 11Wednesday

V5 and V6

V5: safe

Code stopped writing nulls first. Columns checked: zero nulls in staging and prod. Then NOT NULL.

V6: not

Pull request #99: category stored as a name, not a number. Code and column changed together. The old build expects a number and finds a name.

WEEK 11Wednesday

Expand and contract

  • Expand: add the new column, nullable, used by nothing
  • Write: ship code that writes both
  • Read: ship code that reads the new one, handling empty rows
  • Contract: once every running build uses it, remove the old one
WEEK 11Wednesday

Secrets in the pipeline

Secret What it can do
AZURE_WEBAPP_PUBLISH_PROFILE Deploy anything to staging
CLAUDE_CODE_OAUTH_TOKEN Run Claude Code on my account
GITHUB_TOKEN Fresh per job; push the image
Key point

Least privilege: maven-build.yml asks for contents: read and nothing else.

WEEK 11Wednesday

Forks get no secrets

  • A pull request from a fork runs with no secrets and a read-only token
  • That's why Project Pulse's checks need none
Pitfall

Never "fix" a fork's workflow with pull_request_target: it runs with your secrets, and a stranger's code can run with them.

WEEK 11Wednesday

Short-lived beats long-lived

Publish profile

A password that works until someone regenerates it.

OIDC

Azure trusts GitHub's token for this workflow and returns a credential that lasts minutes.

Pitfall

Project Pulse's deploy workflow holds the publish profile. Until #108, it named its Actions by tag.

WEEK 11Wednesday

An agent in CI

The agent

claude.yml runs Claude Code when someone writes @claude in an issue or a comment. It holds a secret, reads text anyone can write, and can reach the network.

  • Guard: it acts only for people with write access (leave that default on)
  • Guard: a read-only GITHUB_TOKEN
  • Guard: Actions pinned to SHAs
Key point

An agent in CI never acts on text from someone outside the team.

WEEK 11Wednesday

Same commit, same build

npm ci

Installs exactly what package-lock.json says. Fails if it disagrees.

npm install

May update the lockfile within package.json's ranges.

Pitfall

Project Pulse, until #108: the pull request workflow ran npm ci; the deploy workflow ran npm install.

WEEK 11Wednesday

Versions and tags

  • A tag marks a baseline: this commit is what we released
  • MAJOR.MINOR.PATCH: breaks, adds, fixes
  • v1.4.2: a patch about thirteen hours after v1.4.1, notes naming the bug and issue #28
  • Today: last tag v1.5.0, 61 merged pull requests ago; pom.xml says 2.0.0

v1.0.0-final-FINAL-really-final is not Semantic Versioning.

WEEK 11Wednesday

Tag your Checkpoint 2

git tag -a v0.1.0 -m "Checkpoint 2: proving slice"
git push origin v0.1.0

Then: Releases, Draft a new release, choose the tag, Generate release notes.

Key point

v0.1.0 at Checkpoint 2, v0.2.0 at Checkpoint 3, v1.0.0 for the MVP.

WEEK 11Wednesday

Feature flags rot

  • A flag ships code switched off: on and off without a deploy
  • Project Pulse: app.reminders.enabled (off in staging)
  • Knight Capital: a reused flag woke Power Peg
Key point

Every flag gets an owner and a removal date. A retired flag is deleted, never repurposed.

WEEK 11Wednesday

Where will your project run?

  • Whose account hosts it, and who can turn it off?
  • Who pays, and what happens when a credit runs out?
  • Who owns it after December, and after May?
  • What is staging for you?
  • What data will it hold?
Pitfall

A cloud account bills by the hour. Set a cost alert the day you create it.

WEEK 11Wednesday

Over the wall

Developers

Write features. Rewarded for change. Hand the release over the wall.

Operations

Keep production up. Rewarded for stability. Catch what comes over.

Ask the room

Every release is a negotiation, every outage a search for someone to blame. What would you change?

WEEK 11Wednesday

DevOps: you build it, you run it

"You build it, you run it."

Werner Vogels, Amazon

Key point

One team owns a change from commit to production.

WEEK 11Wednesday

CALMS

Means You've done it
Culture One team, commit to production You deploy what you build
Automation Done twice by hand? Pipeline step Today's workflows
Lean Small batches, flowing Team 2
Measurement Numbers, not opinions DORA; observability, week 12
Sharing Dashboards, knowledge, blameless postmortems Reliability
WEEK 11Wednesday

How DevOps measures itself

Speed

Deployment frequency. Change lead time, commit to production. Recovery time after a failed deploy.

Stability

Change fail rate. Deployment rework rate.

Key point

DORA: "speed and stability are not tradeoffs."

WEEK 11Wednesday

DevOps and SRE

class SRE implements DevOps { }

Google's own summary, from The Site Reliability Workbook: "class SRE implements interface DevOps."

WEEK 11Wednesday

In an interview: "What is DevOps?"

  • What: one team owns software from commit to production, instead of handing releases to operations
  • How: automation and small, frequent changes, so each failure is small and quick to fix
  • How you know: the DORA metrics
  • Then one example from your project: your pipeline, your gate, your rollback
WEEK 11Wednesday

Red made green

The agent

Asked to fix a failing build, an agent can add @Disabled, set continue-on-error, grow a baseline, or regenerate the lockfile. Each one turns the check green.

Key point

Ask of every such diff: does this make red green without fixing anything?

WEEK 11Wednesday

The agent and the pipeline

Delegate

Draft a workflow. Explain a failed run's log. Draft release notes. Split a migration into expand and contract. Spot unpinned Actions.

Keep

What's required on main, and who may bypass it. When production changes. Which secrets exist. Whether a schema change can roll back.

WEEK 11Wednesday

Your week

  • Friday studio: the gate on your repository, the Protect main rules, your charter line, and an open deployment question in section 7
  • Checkpoint 2, by Friday: demo from a tagged v0.1.0 with release notes
  • Assignment 4, Triage the analyzers: out today; your pull request leaves the pipeline green
Key point

Checked on every pull request, blocked when red, deployed from what was checked, undoable when it goes wrong.

CI/CD and Continuous Deployment

→ space PgDn
Next step or slide
← PgUp
Back
↓ S
Skip to the next slide
O
Overview of all slides
N
Speaker notes
B
Black the screen
Ctrl+P
Print / PDF handout, one slide per page