Get Started with CI/CD Pipelines: Your First Concrete Step Today

CI/CD Pipeline: The Essentials in One Article — Real Code, Diagrams, and Concrete Steps, Excerpts from a 20-Lesson Course.

Get Started with CI/CD Pipelines: Your First Concrete Step Today

The best way to learn CI CD Pipeline is by doing. This article gives you a head start with practical excerpts from a 20-lesson course — enough to get your first result today.

tl;dr
  • Introduction to CICD
  • Continuous Integration
  • Code Quality
  • Pipeline Optimization
  • Continuous Deployment
~$ cat ./parcours.md # CI CD Pipeline — 6 chapters
01
Introduction to CICD
→ Chapter 00.1 — CI/CD Philosophy: Why automate?→ Chapter 00.2 — The CI/CD tools ecosystem+ 1 more lessons
02
Continuous Integration
→ Chapter 01.1 — Git branch strategies→ Chapter 01.2 — Automated builds and advanced YAML pipelines+ 1 more lessons
03
Code Quality
→ Chapter 02.1 — Static analysis with SonarQube→ Chapter 02.2 — Security in CI/CD: SAST, DAST and dependencies+ 1 more lessons
04
Pipeline Optimization
→ Chapter 03.1 — Pipeline Optimization: Cache, Parallelization and Matrices→ Chapter 03.2 — Docker builds optimization+ 1 more lessons
05
Continuous Deployment
→ Chapter 04.1 — Advanced deployment strategies→ Chapter 04.2 — Environments, Secrets and Rollback+ 1 more lessons
06
Monitoring and Observability
→ Chapter 05.1 — Post-deployment Monitoring and Observability→ Chapter 05.2 — SLO, SLA and DORA Metrics
🏁
Final project
→ You leave with a concrete and demonstrable project

Code Coverage and Quality Thresholds

Chapter 02 • Lesson 03 • Duration: 45 min

NOTE🎯 Objectives
  • Understand what code coverage is and its limitations
  • Measure coverage with standard tools (pytest-cov, jest, JaCoCo)
  • Define smart thresholds (line, branch, mutation)
  • Block a PR if coverage drops
  • Visualize reports in Codecov or SonarQube

1. What is code coverage?

Code coverage measures the percentage of lines (or branches, conditions, functions) executed by your automated tests.

TypeMeasureExample
Line Coverage% of executed lines80 % = 80 out of 100 lines touched
Branch Coverage% of conditional branches testedif/else, switch — both paths must pass
Function Coverage% of called functionsAre all exported functions tested?
Statement Coverage% of executed statementsClose to line coverage
Mutation Coverage% of mutations detected by testsMore reliable but expensive (mutation testing)
WARNING⚠️ Classic pitfall

100 % coverage does NOT mean 100 % quality. You can have 100 % lines executed without verifying the results. assert is just as important as executing the code.

2. Coverage in Python with pytest-cov

output
pip install pytest pytest-cov

# Run tests with coverage
pytest --cov=mon_module --cov-report=term --cov-report=html

# Console output:
# Name            Stmts   Miss  Cover
# -------------------------------------
# mon_module.py     50      5    90%
# -------------------------------------
# TOTAL             50      5    90%

# Interactive HTML report in htmlcov/index.html

Configuration via pyproject.toml

output
[tool.pytest.ini_options]
addopts = "--cov=src --cov-report=term-missing --cov-report=xml --cov-fail-under=80"

[tool.coverage.run]
source = ["src"]
omit = [
    "*/tests/*",
    "*/migrations/*",
    "*/__init__.py"
]

[tool.coverage.report]
exclude_lines = [
    "pragma: no cover",
    "raise NotImplementedError",
    "if __name__ == .__main__.:",
]
fail_under = 80
show_missing = true

3. Coverage in JavaScript with Jest

output
npm install --save-dev jest

# package.json
{
  "scripts": {
    "test": "jest",
    "test:coverage": "jest --coverage"
  },
  "jest": {
    "collectCoverageFrom": [
      "src/**/*.{js,ts}",
      "!src/**/*.d.ts",
      "!src/index.ts"
    ],
    "coverageThreshold": {
      "global": {
        "branches": 75,
        "functions": 80,
        "lines": 80,
        "statements": 80
      }
    },
    "coverageReporters": ["text", "lcov", "html", "cobertura"]
  }
}

# Run
npm run test:coverage

# If threshold not met:
# Jest: "global" coverage threshold for lines (80%) not met: 73.5%
# → Build FAILS

4. Coverage in Java with JaCoCo

output
<!-- pom.xml -->
<plugin>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
  <version>0.8.11</version>
  <executions>
    <execution>
      <goals><goal>prepare-agent</goal></goals>
    </execution>
    <execution>
      <id>report</id>
      <phase>test</phase>
      <goals><goal>report</goal></goals>
    </execution>
    <execution>
      <id>jacoco-check</id>
      <goals><goal>check</goal></goals>
      <configuration>
        <rules>
          <rule>
            <element>BUNDLE</element>
            <limits>
              <limit>
                <counter>LINE</counter>
                <value>COVEREDRATIO</value>
                <minimum>0.80</minimum>
              </limit>
            </limits>
          </rule>
        </rules>
      </configuration>
    </execution>
  </executions>
</plugin>

mvn clean test
# Report in target/site/jacoco/index.html

5. Defining smart thresholds

Project typeRecommended threshold
Critical (banking, healthcare, aerospace)90-95 %
SaaS / Web app production80-85 %
Backend API75-85 %
Frontend (UI logic)60-70 %
Prototype / MVP40-60 %
Utility script0-30 % (often unnecessary)
TIP💡 Realistic strategy

Instead of an absolute threshold, require that coverage does not decrease compared to the main branch. Codecov and SonarQube do this natively.

6. GitHub Actions integration

output
name: CI with Coverage

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      
      - name: Install
        run: pip install -e ".[dev]"
      
      - name: Tests + coverage
        run: pytest --cov --cov-report=xml --cov-report=term --cov-fail-under=80
      
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          file: ./coverage.xml
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: true

7. Codecov: visualize and compare

codecov.yml for customization

output
coverage:
  status:
    project:
      default:
        target: 80%
        threshold: 1%
    patch:
      default:
        target: 90%
        threshold: 5%

comment:
  layout: "header, diff, flags, files"
  behavior: default
  require_changes: false

ignore:
  - "tests/**"
  - "**/__init__.py"
  - "migrations/**"

Managing artifacts and registries

Chapter 03 • Lesson 03 • Duration: 45 min

NOTE🎯 Objectives
  • Understand what an artifact and a registry are
  • Store and share artifacts (zip, jar, wheel) in GitHub Actions
  • Push Docker images to Docker Hub, GHCR, AWS ECR
  • Manage semantic versioning of artifacts
  • Set up retention rules to avoid cost explosion

1. What is an artifact?

An artifact is any file produced by a build and intended to be used later:

Artifact typeExampleTypical registry
Container imagedevforge-api:1.2.3 (Docker)Docker Hub, GHCR, ECR, Quay
Python packagemy-lib-1.0.0.whlPyPI, AWS CodeArtifact, GitHub Packages
npm packagemy-lib-1.0.0.tgznpm registry, GitHub Packages
Java JARmy-app-1.0.jarMaven Central, Nexus, JFrog Artifactory
Compiled binarymy-cli-linux-amd64GitHub Releases, S3
Helm chartmy-chart-1.0.0.tgzChartMuseum, OCI registries
Generic ZIP filebuild-output.zipGitHub Actions Artifacts, S3

2. GitHub Actions artifacts (intra-workflow)

Upload an artifact

output
- name: Build wheel
  run: python -m build

- name: Upload wheel as artifact
  uses: actions/upload-artifact@v4
  with:
    name: python-wheel
    path: dist/*.whl
    retention-days: 30

Download in a subsequent job

output
deploy:
  needs: build
  runs-on: ubuntu-latest
  steps:
    - name: Download wheel
      uses: actions/download-artifact@v4
      with:
        name: python-wheel
        path: ./dist
    
    - name: Install
      run: pip install dist/*.whl
TIP

GitHub artifacts are free up to 500 MB per public repo and expire by default after 90 days.

3. Container registries compared

RegistryCostAdvantagesDisadvantages
Docker HubFree (public) / 5 $/user (private)Most popular, large ecosystemRate limits on pulls
GHCR (GitHub)Free (public) / included with GitHubNative GitHub integrationLess known
AWS ECR0.10 $/GB/monthIAM security, auto scan, integrated with ECS/EKSRegion-specific
GCR / Artifact Registry0.10 $/GB/monthIntegrated with GCP, multi-formatGCP lock-in
Azure ACRBasic 5 $/monthIntegrated with AzureAzure lock-in
Quay.ioFree (public) / paid (private)Strong vulnerability detectionLess support
Harbor (self-hosted)Free (but ops)No external dependency, full controlMust maintain yourself

4. Push to Docker Hub from GitHub Actions

output
- name: Login Docker Hub
  uses: docker/login-action@v3
  with:
    username: ${{ secrets.DOCKERHUB_USERNAME }}
    password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: |
      myuser/myapp:latest
      myuser/myapp:${{ github.sha }}
      myuser/myapp:${{ github.ref_name }}
    platforms: linux/amd64,linux/arm64
    cache-from: type=gha
    cache-to: type=gha,mode=max

5. Push to GHCR (GitHub Container Registry)

output
- name: Login to GHCR
  uses: docker/login-action@v3
  with:
    registry: ghcr.io
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
  uses: docker/build-push-action@v5
  with:
    push: true
    tags: |
      ghcr.io/${{ github.repository }}:latest
      ghcr.io/${{ github.repository }}:${{ github.sha }}
TIP

GHCR requires no additional secret: the auto-generated GITHUB_TOKEN is sufficient.

6. Push to AWS ECR

output
- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::123456789012:role/github-actions-ecr
    aws-region: eu-west-3

- name: Login to ECR
  id: ecr
  uses: aws-actions/amazon-ecr-login@v2

- name: Build and push
  uses: docker/build-push-action@v5
  with:
    push: true
    tags: |
      ${{ steps.ecr.outputs.registry }}/myapp:latest
      ${{ steps.ecr.outputs.registry }}/myapp:${{ github.sha }}

7. Semantic versioning of images

SemVer convention: MAJOR.MINOR.PATCH

TagWhen to use it
1.2.3Exact immutable version (strict production)
1.2Latest patch of minor 1.2
1Latest minor of major 1
latestMost recent (avoid in prod!)
sha-abc1234Commit-based tag
main / developLatest of the branch
pr-42Specific to a Pull Request
v1.2.3-rc.1Release candidate

With docker/metadata-action

output
- name: Generate tags
  id: meta
  uses: docker/metadata-action@v5
  with:
    images: myuser/myapp
    tags: |
      type=ref,event=branch
      type=ref,event=pr
      type=semver,pattern={{version}}
      type=semver,pattern={{major}}.{{minor}}
      type=semver,pattern={{major}}
      type=sha,prefix=sha-,format=short
      type=raw,value=latest,enable={{is_default_branch}}

# Automatic output according to context:
# - on main: latest, sha-abc1234, main
# - on tag v1.2.3: 1.2.3, 1.2, 1, sha-abc1234
# - on PR #42: pr-42, sha-abc1234

Chapter 00.1 — CI/CD Philosophy: Why automate?

NOTEObjective of this lesson — Understand the problems of traditional software development, discover why CI/CD automation has become essential, and learn the fundamental principles that guide a modern pipeline.

1. The world before CI/CD — The “Integration Hell”

Before adopting CI/CD practices, development teams worked in silos for weeks or months on separate branches. When they tried to integrate their code, the result was often disastrous. This phenomenon was called Integration Hell.

🔴 Before CI/CD

🟢 With CI/CD

WARNINGShocking statistic — According to the DORA 2023 report, “elite” teams deploy multiple times per day with a deployment failure rate below 5 %, compared to once a month or less for “low performer” teams.

2. The cost of a bug — The “Shift Left” rule

The “Shift Left” principle means detecting and fixing problems as early as possible in the development cycle. The later a bug is detected, the more expensive it is to fix.

CI/CD allows problems to surface at commit time, drastically reducing the cost of fixes. Automated tests, static code analysis and security scans run on every push, long before the code reaches production.

3. The three pillars: CI, CD (Delivery) and CD (Deployment)

🔵 CI — Continuous Integration

Developers integrate their code into a common branch multiple times a day. Each integration triggers an automated pipeline: compilation, unit tests, code analysis.

Goal: detect conflicts and bugs quickly.

🟡 CD — Continuous Delivery

The code is always in a deployable state. After CI, the pipeline automatically prepares a release (package, Docker image) ready to be deployed to any environment.

Goal: be able to deploy at any time, with possible human approval.

🟢 CD — Continuous Deployment

Every commit that passes the tests is automatically deployed to production, without human intervention. This is the ultimate level of automation, used by Netflix, Amazon, Google.

Goal: eliminate any delay between code and user value.

PracticeDeployment frequencyHuman approvalRequired confidence level
ManualQuarterly / YearlyAlwaysLow (process)
CI onlyWeekly / MonthlyAlwaysMedium (basic tests)
CI + CD DeliveryDaily / WeeklyOptionalHigh (complete tests)
CI + CD DeploymentMultiple times/dayNeverVery high (tests + monitoring)

4. The CI/CD pipeline — Overview

A CI/CD pipeline is a chain of automated steps that transforms a code commit into an application deployed to production.

StepDescriptionCommon toolsTypical duration
CodeDeveloper pushes code to GitGit, GitHub, GitLab
BuildCompilation, dependency resolutionMaven, npm, Gradle, Docker1–5 min
Unit testFast tests at function levelJUnit, Jest, pytest1–3 min
Quality analysisCode coverage, linting, securitySonarQube, ESLint, Snyk2–5 min
PackageCreate a deployable artifactDocker, JAR, ZIP, Helm2–10 min
Integration testTests on a complete environmentPostman, Cypress, k65–15 min
Deploy StagingDeployment to test environmentKubernetes, ECS, Heroku2–5 min
Deploy ProdDeployment to productionRolling, Blue/Green, Canary2–10 min
MonitorPost-deployment monitoring and alertsPrometheus, Grafana, DatadogContinuous

5. DORA metrics — Measuring DevOps performance

The DORA project (DevOps Research and Assessment) identified four key metrics that measure the effectiveness of a DevOps organization. These metrics help position your team and define improvement goals.

📈 Deployment Frequency

go-further

This article covers the most useful excerpts — the full CI CD Pipeline course (7 chapters, 20 lessons, corrected exercises and final project) takes you all the way.

./access-the-full-course free course: Mastering Claude Code

FAQ

How long does it take to learn CI CD Pipeline?
With a structured progression (7 chapters, 20 short and practical lessons), you reach an operational level in a few weeks at 30 to 60 minutes per day. The key is to practice each concept immediately.
Are there any prerequisites?
Basic computer science knowledge is sufficient. If you can use a terminal and read simple code, you are ready.
Where to start concretely?
Reproduce the commands in this article, then follow the full CI CD Pipeline course: it chains the 20 lessons in order, with exercises and a final project.

📬 Want to receive this type of guide every week? Subscribe for free — real code, zero fluff.