0

CI/CD — Continuous Integration and Continuous Deployment defined precisely

Beginner5 min read·eng-18-001
interview

Concept

CI/CD (Continuous Integration / Continuous Delivery or Deployment) — a set of practices that automate the testing, building, and deployment of code changes.

Continuous Integration (CI): Developers merge code changes frequently (multiple times per day). Each merge triggers automated tests and build checks. The goal: catch integration failures fast, not days later.

Continuous Delivery (CD): Ensuring code is always in a deployable state. After CI passes, a deployment to production is possible at any time — but a human still clicks the deploy button.

Continuous Deployment: Like Continuous Delivery, but the deploy to production is also automated. Every passing commit goes to production automatically.

A typical CI pipeline:

  1. Developer pushes code.
  2. CI triggers: install dependencies, run static analysis (PHPStan, Larastan), run tests (PHPUnit).
  3. If all pass: artifact is built (Docker image, zip archive).
  4. CD: deploy to staging, run smoke tests, deploy to production.

Benefits of CI/CD:

  • Bugs found at merge time, not deployment time.
  • No "integration hell" — small, frequent merges stay small.
  • Reproducible builds — same environment every time.
  • Fast feedback loop — know if your change breaks something in minutes.

Common CI tools: GitHub Actions, GitLab CI, CircleCI, Jenkins, Bitbucket Pipelines.

Laravel + CI: php artisan test, ./vendor/bin/phpstan analyse, ./vendor/bin/pint --test in the CI pipeline.

Code Example

yaml
# .github/workflows/ci.yml — GitHub Actions CI pipeline for Laravel
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_DATABASE: testing
          MYSQL_ROOT_PASSWORD: password
        ports:
          - 3306:3306
        options: --health-cmd="mysqladmin ping" --health-interval=10s

    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.4'
          extensions: pdo, pdo_mysql, mbstring
          coverage: pcov

      - name: Cache Composer packages
        uses: actions/cache@v3
        with:
          path: vendor/
          key: ${{ runner.os }}-php-${{ hashFiles('composer.lock') }}

      - name: Install dependencies
        run: composer install --no-interaction --prefer-dist

      - name: Copy env
        run: cp .env.ci .env

      - name: Generate key
        run: php artisan key:generate

      - name: Run static analysis
        run: ./vendor/bin/phpstan analyse --no-progress

      - name: Check code style
        run: ./vendor/bin/pint --test

      - name: Run tests
        run: php artisan test --parallel --coverage --min=80
        env:
          DB_CONNECTION: mysql
          DB_HOST: 127.0.0.1
          DB_PORT: 3306
          DB_DATABASE: testing
          DB_USERNAME: root
          DB_PASSWORD: password

  deploy-staging:
    needs: test          # only runs if test job passes
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4
      - name: Deploy to staging
        run: ./scripts/deploy.sh staging
php
// .env.ci — CI-specific environment
# .env.ci
APP_ENV=testing
DB_CONNECTION=mysql
CACHE_DRIVER=array
QUEUE_CONNECTION=sync
MAIL_MAILER=array