Skip to content
CONAKRY · LAMBANYI — +224614686869 contact@visiodev.net
Français Request a quote
← All articles
DEVOPS 5 MIN

A CI/CD pipeline that fits on one page

A pipeline the whole team can read is better than an exhaustive pipeline nobody understands. Here is the one we set up by default.

Source code displayed on a laptop screen in the dark

Five steps, not twelve

Install, test, build, deploy to staging, deploy to production. Everything else is a convenience you will pay for in confusion.

We have inherited pipelines several hundred lines long, with conditional steps, scripts called by other scripts, and only one person able to explain why deployment failed on Fridays. The day that person goes on leave, the team stops deploying. A pipeline must be readable, understandable and modifiable by any developer on the team in ten minutes.

Step 1: install, reproducibly

The first step fetches the code and installs the dependencies. It seems trivial; yet this is where most "it works on my machine" problems are born.

  • Versions are locked. The dependency lock file (composer.lock, package-lock.json) is versioned, and the pipeline installs exactly what it contains, nothing more.
  • The environment is fixed. Same language version as in production, in the same container image.
  • The cache is used for dependencies, so the step takes a few seconds rather than a few minutes.

Step 2: test, fast and every time

Tests run on every push, on every branch. Not just before a release: every time. A test that only runs once a month ends up permanently broken, and nobody looks at it anymore.

In this step we group everything that checks the code without deploying it:

  • static analysis and formatting, which fail within seconds;
  • unit tests;
  • integration tests, with a disposable database created for the occasion;
  • a dependency audit, which flags libraries with a known vulnerability.

The constraint we set ourselves is duration: under ten minutes. Beyond that, developers stop waiting for the result, move on to something else and discover the failure an hour later. If the tests get too long, we parallelize or split them, but we do not delete them.

A flaky test, which fails one time in ten for no reason, is treated as an outage: it is fixed or quarantined the same day. Otherwise the team gets used to rerunning the pipeline until it passes, and the day the failure is real, nobody believes it anymore.

Step 3: build once

The build produces the artifact that will be deployed: a container image, an archive, a package. The key principle: build once, and deploy the same artifact everywhere. What goes to production is exactly what was validated in staging, byte for byte.

Rebuilding for each environment means risking that a dependency has changed in the meantime. The difference between environments comes only from configuration: environment variables, secrets, service addresses. Never from the code.

The artifact carries a traceable identifier, usually the commit hash. Faced with any incident, you know exactly which version is running and what code it contains.

Step 4: deploy to staging, automatically

Every merge into the main branch triggers an automatic deployment to staging. Nobody has to ask for it. Staging therefore always reflects the real state of the code, and the business can test new features as soon as they are ready.

This deployment is followed by a few quick checks: the home page responds, login works, the database migrations have run. Not an exhaustive test suite, just enough to know the application is alive.

Step 5: deploy to production, on a human decision

The production release uses the same script as staging, with the same artifact. The only difference: it is triggered by a person, with one click. This approval is not bureaucratic; it lets you choose the moment, avoid Friday evenings and warn users if needed.

Two rules go with it:

  • Rollback is planned. Redeploying the previous version should take a minute and require no thought. Since the previous artifact still exists, it is a simple redeployment.
  • Migrations are compatible. A database change must work with both the old and the new version of the code, so that rollback remains possible.

Secrets have no place in the repository

Database passwords, API keys, certificates: none of them should appear in the code or in the pipeline file. They are stored in the continuous integration platform's secrets manager, injected at deployment time, and different for each environment. Staging never has access to production secrets.

This is also what lets you open the pipeline to the whole team without worry: everyone can read and modify it, nobody sees the keys.

What we deliberately left out

We could have added intermediate environments, progressive rollouts by percentage of users, load tests on every merge, multiple approvals. Some projects need them. Most do not, and certainly not at the start.

Every step you add must answer a real incident or an identified risk. "You never know" is not a justification: it is the shortest route to a pipeline nobody understands.

The page in question

Our starting rule fits in one sentence: if the pipeline configuration file does not fit on one screen, it is too complicated. The details live in clearly named scripts that you can run by hand from your own machine. The pipeline just chains them together.

A good pipeline is boring: it turns green, it deploys, and nobody talks about it. That is exactly what you want from it.

If your team dreads releases, the problem is rarely the code. It is almost always the path that takes it to production.

Share

Further reading