Git Course 0%

CI/CD on GitLab

Intermediate GitLab UI ≈ 12 min

What you will learn

  • What a pipeline, stage, job and runner are on GitLab
  • How to read a failing job log and find the line that matters
  • Enough of .gitlab-ci.yml to recognize what is being run

After this lesson you can

  • I can diagnose a red pipeline on my own merge request and fix the common causes

Why this matters

The pipeline is the gatekeeper on every merge request, and when it turns red the merge button locks. Most of the time the cause is your change and the fix takes a minute, but only if you can find it. This lesson is about reading the result; Section 14 is about the ideas behind it and writing the file.

The vocabulary, briefly

Word Means
Pipeline Everything that runs for one push: all the stages and jobs
Stage A phase, such as test or deploy; stages run in order
Job One unit of work in a stage, such as tests or lint-docs; jobs in the same stage run in parallel
Runner The machine that executes a job
Artifact A file a job produces and keeps, such as a report or a built site

The playground's pipeline has one stage, test, with two jobs, tests and lint-docs. A push runs both; if either fails, the pipeline is red.

Where you see it

Place Shows
The merge request's Overview The pipeline's status and each job as a small icon
Build → Pipelines Every pipeline for the project, with branch, commit and who triggered it
Build → Jobs Every job, useful for finding a flaky one
A commit page The pipeline for that commit

Statuses: passed (green), failed (red), running (blue), pending (waiting for a runner), canceled, skipped, and warning for a job that failed but was marked allow_failure, which does not block the merge.

Reading a failure

The whole skill is four steps, and the third is where most people give up too early.

  1. Open the failed job. On the merge request, click the red icon; on the pipeline page, click the job's name. Do not read the pipeline page for the reason: it only says which job failed.
  2. Scroll to the bottom of the log. The last twenty lines almost always contain the cause. The top is setup noise: cloning, installing, versions.
  3. Find the first real error, not the last line. The last line is usually ERROR: Job failed: exit code 1, which says only that something failed. The useful line is above it, often a file name and a line number.
  4. Match it to your change. If the error names a file you touched, it is yours. If it names something you never opened, it may be a pre-existing failure or a flaky job; check whether the same job fails on main.

A Markdown lint failure, which is the one a documentation contributor meets most, looks like this near the end of the log:

Text
docs/getting-started.md:31 MD001/heading-increment Heading levels should only increment by one level at a time [Expected: h2; Actual: h3]
ERROR: Job failed: exit code 1

File, line, rule, and what it expected. Fix that line, commit, push; the pipeline runs again automatically.

Retrying, and when it is legitimate

Each job has a Retry button, and the pipeline has Retry for all failed jobs. Retrying is right when the failure was the infrastructure: a timeout, a runner that vanished, a network error fetching a dependency. It is not right when the log names your file: the same code produces the same result, and retrying only wastes minutes.

A job that fails intermittently on unchanged code is flaky, and it deserves an issue rather than a habit of retrying.

Reading .gitlab-ci.yml

The pipeline is defined by a file in the repository, so you can read it without asking anyone. The playground's:

.gitlab-ci.yml
stages:
  - test

tests:
  stage: test
  image: python:3.12
  script:
    - python -m unittest discover -s tests -v

lint-docs:
  stage: test
  image: node:20
  script:
    - npx --yes markdownlint-cli "**/*.md" --ignore node_modules

Four things to recognize:

  • stages lists the phases in order.
  • Each top-level name (tests, lint-docs) is a job.
  • image is the environment the job runs in, which is why the pipeline's Python version can differ from yours (lesson 1.4).
  • script is the commands, run in order. You can run these yourself, locally, before pushing — which is the single best way to avoid red pipelines.

That last point is worth acting on: the script lines are the contract. Running npx markdownlint-cli "**/*.md" locally takes ten seconds and catches what the pipeline would catch ten minutes later.

How to do it

There is no git pipeline command; pipelines are GitLab's. What the terminal gives you is the ability to run the same checks before pushing:

Terminal
$ python3 -m unittest discover -s tests -v
$ npx --yes markdownlint-cli "**/*.md" --ignore node_modules

Read .gitlab-ci.yml and run its script lines. If they pass locally, the pipeline usually passes too.

Common mistakes

  • Reading only the last line of the log. exit code 1 is the symptom; the cause is above it.
  • Retrying a real failure. The same code fails the same way; read the log instead.
  • Assuming a red pipeline is your fault. Check whether the same job fails on main; a broken main is everyone's problem, not yours.
  • Not running the pipeline's own commands locally. They are written down in .gitlab-ci.yml.
  • Pushing repeatedly to see whether it passes. Each attempt costs minutes and clutters the merge request.

Try it yourself

Goal: break the pipeline on purpose and fix it from the log.

  1. On a branch in your practice project, edit docs/faq.md and introduce a Markdown lint error: put a #### heading directly under a ##.
  2. Commit and push, and open the merge request.
  3. When the pipeline turns red, open the failing job and find the line naming the file, line number and rule.
  4. Fix that line, commit, push, and watch the pipeline run again.
  5. Before the next push, run the job's own command locally and confirm it reports the same thing.

Expected result: the log names docs/faq.md, a line number and MD001; after the fix the pipeline is green; the local command agrees with the pipeline.

Show solution

Step 5 is the habit worth keeping. The pipeline's script lines are the exact checks, so running them locally turns a ten-minute round trip into a ten-second one. If your project's pipeline needs credentials you do not have, run the parts that do not, which is usually the linting.

Check yourself

1. A job log ends with ERROR: Job failed: exit code 1. What should you read?
2. When is retrying a failed job the right response?
3. Where can you find exactly what the pipeline runs?

Key terms

Pipeline Continuous integration (CI) Continuous delivery / deployment (CD) Artifact Logs (program output)